带位图的 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);
}
我在使用 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);
}