带位图的 RecyclerView

RecyclerView with Bitmap

我在使用 recyclerview 时遇到问题:当我在列表中上下移动时,某些行的图像会被交换(或者通常有几行与其他行的图像设置在一起)。我认为问题出在适配器上,但我不明白出了什么问题。

myAdapter.java中的这个:

public class myAdapter extends RecyclerView.Adapter<myAdapter.MyViewHolder> {

    private List<myItem> myList;
    private Context context;

    public class MyViewHolder extends RecyclerView.ViewHolder {
        public ImageView photo;
        public TextView name;

        public MyViewHolder(View view) {
            super(view);
            photo = (ImageView) view.findViewById(R.id.rowPhoto);
            name = (TextView) view.findViewById(R.id.rowName);
        }
    }


    public myAdapter(List<myItem> myList,Context context) {
       this.myList = myList;
       this.context = context;
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.row_custom, parent, false);

        return new MyViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        myItem c = myList.get(position);

        if(c.getPathFoto()!=null){ 
            File f = new File(c.getPathPhoto());
            Bitmap b = decodeFile(f);
            holder.photo.setImageBitmap(b);
        }

        holder.name.setText(c.getName());
    }



    public Bitmap decodeFile(File f) {
        try {
            // Decode image size
            BitmapFactory.Options o = new BitmapFactory.Options();
            o.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(new FileInputStream(f), null, o);

            // The new size we want to scale to
            final int REQUIRED_SIZE=70;

            // Find the correct scale value. It should be the power of 2.
            int scale = 1;
            while(o.outWidth / scale / 2 >= REQUIRED_SIZE &&
                    o.outHeight / scale / 2 >= REQUIRED_SIZE) {
                scale *= 2;
        }

        // Decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
        } catch (FileNotFoundException e) {}
        return null;
    }

}

所有(我使用的)图像之前都已保存在 /data/data/myapp/app_data/imageDir 中(例如 /data/data/myapp/app_data/imageDir/21432342.png)。

我该如何解决这个问题?

我认为你没有在图像为空时清除图像。

尝试将您的 OnBind 方法更改为:

@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
    myItem c = myList.get(position);

    if(c.getPathFoto()!=null){ 
        File f = new File(c.getPathPhoto());
        Bitmap b = decodeFile(f);
        holder.photo.setImageBitmap(b);
    } else {
        holder.photo.setImageBitmap(null);
    }

    holder.name.setText(c.getName());
}

你肯定有并发问题。 RecyclerView 将重新使用该视图并对其调用 onBindViewHolder。您的方法 onBindViewHolder 需要时间来加载和设置位图。

简单(且肮脏)的解决方案:
在方法上添加一个 synchronized。此解决方案对 UI.

不是很好
@Override
public synchronized void onBindViewHolder(MyViewHolder holder, int position) {
    myItem c = myList.get(position);

    if(c.getPathFoto()!=null){ 
        File f = new File(c.getPathPhoto());
        Bitmap b = decodeFile(f);
        holder.photo.setImageBitmap(b);
    }

    holder.name.setText(c.getName());
}

好的解决方案:
您必须使用其他线程来解码您的位图。在调用 .setImageBitmap(Bitmap) 之前,检查它是否始终是正确的位图。例如,您可以通过设置支架中的位置来实现。

嗯,你可以试试像 Picasso 这样的第三方库或者 glide 来让事情变得更简单 Picasso Glide

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        myItem c = myList.get(position);          
        Picasso.with(context)
               .resize(desiredWidth,desiredHeight)
               .load(new File(c.getPathPhoto())).into(holder.photo);

        }