我有一个习惯ListView
,我会展示一些从本地数据库中检索到的武器。我总共有 88 行,每次getView()
调用时,每行都会设置一个文本和一个图像。快速滚动时出现ListView
滞后,垃圾收集器变得疯狂,每秒删除大约 1M 个对象。我不明白为什么。
在我发布我的Adapter
实现之前,先解释一下 Image 是如何设置的。我的Weapon类只是一个带有 setter 和 getter 的数据持有者。这就是创建数据库时如何设置名称和图像的方式(是的,这可能看起来很奇怪,但所有其他解决方案的工作速度都更慢):
private Weapon buildWeapon(Cursor cursor) {
Weapon w = new Weapon();
w.setId(cursor.getLong(0));
w.setName(cursor.getString(1));
w.setImage(Constants.ALL_WEAPON_IMAGES[(int) cursor.getLong(0)-1]);
return w;
}
所以我有一个Array
包含所有武器图像的R.drawable.somegun
. 数据结构的实现方式使得 ID-1 始终指向 my 中正确的可绘制引用Array
。Weapon 类中的图像字段是一个Integer
. 现在你知道我的getImage()
方法是如何工作的,下面是我的Adapter
:
public class Weapon_Adapter extends BaseAdapter {
private List<Weapon> items;
private LayoutInflater inflater = null;
private WeaponHolder weaponHolder;
private Weapon wp;
static class WeaponHolder {
public TextView text;
public ImageView image;
}
// Context and all weapons of specified class are passed here
public Weapon_Adapter(List<Weapon> items, Context c) {
this.items = (List<Weapon>) items;
inflater = LayoutInflater.from(c);
Log.d("Adapter:", "Adapter created");
}
@Override
public int getCount() {
return items.size();
}
@Override
public Weapon getItem(int position) {
return items.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
wp = (Weapon) getItem(position);
if (convertView == null) {
convertView = inflater.inflate(R.layout.category_row, null);
weaponHolder = new WeaponHolder();
weaponHolder.text = (TextView) convertView
.findViewById(R.id.tvCatText);
weaponHolder.image = (ImageView) convertView
.findViewById(R.id.imgCatImage);
convertView.setTag(weaponHolder);
}
weaponHolder = (WeaponHolder) convertView.getTag();
weaponHolder.text.setText(wp.getName());
weaponHolder.image.setImageResource(wp.getImage());
// weaponHolder.image.setImageResource(R.drawable.ak74m);
return convertView;
}}
现在奇怪的是:使用注释掉的行为所有项目静态设置相同的图像会消除所有滞后和 GC,甚至没有调用一次!我不明白..wp.getImage()
返回完全相同的东西,只是R.drawable.name
每种武器不同。但是 GC 会在滚动时删除大量对象和ListView
滞后。任何想法我做错了什么?
更新
我已将设置图像移至 anAsyncTask
并且滞后现在消失了:
public class AsyncImageSetter extends AsyncTask<Void, Void, Void> {
private ImageView img;
private int image_resId;
private Bitmap bmp;
private Context c;
public AsyncImageSetter(Context c, ImageView img, int image_ResId, Bitmap bmp) {
this.img = img;
this.image_resId = image_ResId;
this.bmp = bmp;
this.c = c;
}
@Override
protected Void doInBackground(Void... params) {
bmp = BitmapFactory.decodeResource(c.getResources(), image_resId);
return null;
}
@Override
protected void onPostExecute(Void result) {
img.setImageBitmap(bmp);
bmp = null;
super.onPostExecute(result);
}
}
但是,在上下滚动整个 List 时,GC 仍然会像疯了一样被调用,并且 RAM 消耗会增加。现在的问题是:如何优化图像回收以避免 RAM 使用量增加?