简体   繁体   中英

Can't set image in RecyclerView using URI

I'm working an app which pulls info from the SQLite database and displays it in a RecyclerView. I am having trouble setting the image in the RecyclerView using the URI.

                    Uri mImageUri=data.getData();
                    imgUri = data.getData();

                    // Get path (Path will be stored in database)
                    String imgToString = imgUri.toString();

                    // Get URI back from path
                    imgUri = Uri.parse(imgToString);

                    // Set ImageView
                    plainImage.setImageURI(imgUri);

                    // Set Glide image
                    Glide.with(this)
                            .asBitmap()
                            .load(imgUri)
                            .into(image);

This is a snippet from my OnActivityResult() after choosing pictures from gallery. Setting the images in a basic activity using this code works. I'm taking the toString() from the URI and saving this in my database. (I will be moving selected pictures to an app folder before taking URIs in final version of app)

However when I retrieve the URI strings from the database, parse them back into URIs, and attempt to set the image in the RecyclerView this method no longer works.

Here is the OnBindViewHolder() from the RecyclerAdapter


    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, final int position) {
        Log.d(TAG, "onBindViewHolder: called.");


        // Load only first image for now
        if(mImages.get(position).size() > 0) {

            tempUri = Uri.parse(mImages.get(position).get(0));

            // Make glide work with image
            Glide.with(mContext)
                    .asBitmap()
                    .load(tempUri)
                    .into(holder.image);

            // With regular ImageView
            holder.imageViewTest.setImageURI(tempUri);
        }
        holder.weight.setText(mWeights.get(position).toString());
        holder.location.setText(mLocations.get(position));
        holder.confidence.setText(mConfidences.get(position).toString());

        // Open item view
        holder.parentLayout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(mContext, ItemView.class);
                // Attach additional data to intent
                intent.putExtra("image_url", mImages.get(position));
                intent.putExtra("location", mLocations.get(position));
                intent.putExtra("confidence", mConfidences.get(position));
                intent.putExtra("weight", mWeights.get(position));
                mContext.startActivity(intent);
            }
        });

    }

The URI seems fine when inspecting the variable. What might be causing this and how can I get the images to set in the RecyclerView?

Thanks

EDIT

Here is the Adapter code

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {


    private static final String TAG = "RecyclerViewAdapter";

    private ArrayList<ArrayList<String>> mImages;
    private ArrayList<Float> mWeights;
    private ArrayList<Float> mConfidences;
    private ArrayList<String> mLocations;
    private ArrayList<Integer> mSharkEntryIds;
    private Context mContext;
    private Uri tempUri;

    public RecyclerViewAdapter(Context context, ArrayList<Integer> ids, ArrayList<ArrayList<String>> images, ArrayList<Float> weights
            , ArrayList<Float> confidences, ArrayList<String> locations) {


        this.mContext = context;
        this.mSharkEntryIds = ids;
        this.mImages = images;
        this.mWeights = weights;
        this.mLocations = locations;
        this.mConfidences = confidences;
    }


    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_list_item, parent, false);
        ViewHolder holder = new ViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, final int position) {
        Log.d(TAG, "onBindViewHolder: called.");


        // Load only first image for now
        if(mImages.get(position).size() > 0) {

            tempUri = Uri.parse(mImages.get(position).get(0));

            // Make glide work with image
            Glide.with(mContext)
                    .asBitmap()
                    .load(tempUri)
                    .into(holder.image);

        }
        holder.weight.setText(mWeights.get(position).toString() + " kg");
        holder.location.setText(mLocations.get(position));
        holder.confidence.setText(mConfidences.get(position).toString() + " %");

        // Open item view
        holder.parentLayout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(mContext, ItemView.class);
                // Attach additional data to intent
                intent.putExtra("id", mSharkEntryIds.get(position));
                intent.putExtra("image_url", mImages.get(position));
                intent.putExtra("location", mLocations.get(position));
                intent.putExtra("confidence", mConfidences.get(position));
                intent.putExtra("weight", mWeights.get(position));
                mContext.startActivity(intent);
            }
        });

    }

    @Override
    public int getItemCount() {
        return mImages.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder{

        CircleImageView image;
        TextView weight;
        TextView confidence;
        TextView location;
        RelativeLayout parentLayout;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);

            image = itemView.findViewById(R.id.thumbnail);
            weight = itemView.findViewById(R.id.biomassText);
            confidence = itemView.findViewById(R.id.confidenceText);
            location = itemView.findViewById(R.id.locationText);
            parentLayout = itemView.findViewById(R.id.parent_layout);
        }
    }

}

Here is the code in which I initialize the RecyclerView

// Vars
private ArrayList<Integer> mSharkEntryIds = new ArrayList<>();
private ArrayList<String> mLocations = new ArrayList<>();
//private ArrayList<String> mImageUrls = new ArrayList<>();
private ArrayList<ArrayList<String>> mImagePaths = new ArrayList<>();
private ArrayList<Float> mConfidences = new ArrayList<>();
private ArrayList<Float> mWeights = new ArrayList<>();
private DatabaseHelper mDatabaseHelper;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_list_view);

    mDatabaseHelper = new DatabaseHelper(this);

    Log.d(TAG, "onCreate: started");

    //initImageBitmaps();

    // Populate list view
    Cursor data = mDatabaseHelper.getSharkEntriesFromDatabase();
    while(data.moveToNext()){
        mSharkEntryIds.add(data.getInt(0));
        mWeights.add(data.getFloat(1));
        mLocations.add(data.getString(2));
        mConfidences.add(data.getFloat(3));
    }
    Log.d(TAG, "onCreate: test");

    // Get associated image paths
    ArrayList<String> photosForEntry;

    for(Integer id : mSharkEntryIds){
        data = mDatabaseHelper.getPhotosWithSharkID(id);
        photosForEntry = new ArrayList<>();
        while(data.moveToNext()){
            photosForEntry.add(data.getString(0));
        }
        mImagePaths.add(photosForEntry);
    }

    initRecyclerView();

}

private void initRecyclerView(){
    Log.d(TAG, "initRecyclerView: init recyclerview");
    RecyclerView recyclerView = findViewById(R.id.recycler_view);
    RecyclerViewAdapter adapter = new RecyclerViewAdapter(this, mSharkEntryIds, mImagePaths, mWeights, mConfidences, mLocations);
    recyclerView.setAdapter(adapter);
    recyclerView.setLayoutManager(new LinearLayoutManager(this));

}

I am thinking that you are doing it wrong, I will assume that you got the paths in string form in your mImages

Do you see this part of your onBindViewHolder :

    ...................
    // Load only first image for now
    if(mImages.get(position).size() > 0) {

        tempUri = Uri.parse(mImages.get(position).get(0));

        // Make glide work with image
        Glide.with(mContext)
                .asBitmap()
                .load(tempUri)
                .into(holder.image);

        // With regular ImageView
        holder.imageViewTest.setImageURI(tempUri);
    }
    ..................

Change it to this:

     ........
    // Load only first image for now
    if(position == 0) {

        tempUri = Uri.parse(mImages.get(position));

        // Make glide work with image
        Glide.with(mContext)
                .asBitmap()
                .load(tempUri)
                .into(holder.image);

        // With regular ImageView
        holder.imageViewTest.setImageURI(tempUri);
    }
    ..............

UPDATE:

Your code seems fine and you say that the Uri's are present in the list, so my guess here is maybe set the layout manager before setting the adapter:

I mean in your initRecyclerView() :

 ..........

//add this first
recyclerView.setLayoutManager(new LinearLayoutManager(this));

//add this next
recyclerView.setAdapter(adapter);

......

I have fixed the issue:

The log included this message:

java.lang.SecurityException(Permission Denial: opening provider com.android.providers.downloads.DownloadStorageProvider from ProcessRecord{985e802 27308:com.oshea.sharkbiomass/u0a82} (pid=27308, uid=10082) requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs)

The problem was in my on click listener for the select photo button.

// Select photo button listener
        btnSelectPhotos.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent();
                intent.setType("image/*");
                intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
                intent.setAction(Intent.ACTION_GET_CONTENT);
                startActivityForResult(intent, 1);
            }
        });

I changed this to:

// Select photo button listener
        btnSelectPhotos.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent();
                intent.setType("image/*");
                intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
                intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
                startActivityForResult(intent, 1);
            }
        });

(Changed ACTION_GET_CONTENT to ACTION_OPEN_DOCUMENT) and it worked.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM