无法使用 URI 在 RecyclerView 中设置图像

Can't set image in RecyclerView using URI

我正在开发一个从 SQLite 数据库中提取信息并将其显示在 RecyclerView 中的应用程序。我无法使用 URI 在 RecyclerView 中设置图像。

                    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);

这是从图库中选择图片后我的 OnActivityResult() 的片段。使用此代码可以在基本 activity 中设置图像。我从 URI 中获取 toString() 并将其保存在我的数据库中。 (在最终版本的应用程序中获取 URI 之前,我会将选定的图片移动到应用程序文件夹)

然而,当我从数据库中检索 URI 字符串,将它们解析回 URI,并尝试在 RecyclerView 中设置图像时,此方法不再有效。

这是来自 RecyclerAdapter 的 OnBindViewHolder()


    @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);
            }
        });

    }

检查变量时 URI 似乎没问题。可能是什么原因造成的,我怎样才能在 RecyclerView 中设置图像?

谢谢

编辑

这是适配器代码

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);
        }
    }

}

这是我初始化 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));

}

我认为你做错了,我假设你在 mImages

中得到了字符串形式的路径

你看到你的这一部分了吗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);
    }
    ..................

改成这样:

     ........
    // 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);
    }
    ..............

更新:

你的代码看起来不错,你说 Uri 出现在列表中,所以我的猜测是在设置适配器之前设置布局管理器:

我的意思是在你的 initRecyclerView():

 ..........

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

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

......

我已经解决了这个问题:

日志包含此消息:

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)

问题出在我的 select 照片按钮的点击侦听器中。

// 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);
            }
        });

我将其更改为:

// 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);
            }
        });

(将 ACTION_GET_CONTENT 更改为 ACTION_OPEN_DOCUMENT)并且有效。