【发布时间】:2015-03-22 15:14:24
【问题描述】:
正如许多教程和Android developers pages too 中所述,我正在使用异步任务将图像作为缩略图加载到 ListView 中。该任务从 SD 卡加载全尺寸图片,调整大小并将其放入列表项布局的 ImageView 中。
一切都很好,除了在快速上下滚动列表后,单个可见元素的图像在获得正确的图像之前会用不同的图像更新两到三遍。
在我看来,这种行为与recycling views in ListView 相关:当异步任务准备在引用视图中注入列表的元素-X 图像时,视图本身可能已经被回收并分配给列表的元素-是的。
我意识到我的代码中存在一些丑,例如,我既没有为缩略图实现易失性缓存也没有实现持久性缓存(针对下一个版本),但问题只是部分被它隐藏了。
我找到了possible solution using libraries for loading image,但我正在研究如何修复我的代码,因为这个问题更普遍地与将异步代码与列表结合使用有关,今天我处理图像,但明天我可能会面对加载文本或任何其他类型的数据时出现同样的问题。
我正在研究的可能解决方案是:
- 通知异步任务它正在处理的列表中的项目,一旦加载的图像仅在项目可见时更新它
- 当列表将视图与元素分离时(我如何检测到这一点?),stop the asynctask
- 覆盖列表的 OnScrollListener 以检查是否发生 OnScroll 事件,如果项目退出可见项目的列表并停止其异步任务(如果存在)。
这些解决方案之一是可行的还是您建议的其他解决方案?
这是我的列表适配器(我在片段中使用可扩展列表):
@Override
public View getChildView(int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
Log.i(TAG, "ExpandableListAdapter.getChildView entered, getting view n. " + groupPosition + "-" + childPosition + ", convertview = " + convertView);
ViewHolder holder;
if (convertView == null) {
convertView = inf.inflate(R.layout.selfie_list_item_layout, parent, false);
holder = new ViewHolder();
holder.date = (TextView) convertView.findViewById(R.id.selfieListItemDateView);
holder.place = (TextView) convertView.findViewById(R.id.selfieListItemPlaceView);
holder.thumb = (ImageView) convertView.findViewById(R.id.selfieListItemThumbView);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
Integer mChildIndex = (Integer) getChild(groupPosition, childPosition);
SelfieItem mChildObj = selfies.get(mChildIndex);
String mText = mChildObj.getDate().toString();
holder.date.setText(mText);
holder.thumb.setImageBitmap(BitmapFactory.decodeResource(convertView.getResources(), R.drawable.selfie_place_holder));
File selfieFile = mChildObj.getFile();
new LoadSelfieTask(mFragmentContext).executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, selfieFile, holder.thumb);
return convertView;
}
以下是异步代码:
@Override
protected Bitmap doInBackground(Object... params) {
File selfieFile = (File)params[0];
Bitmap mySrcBitmap = null;
Bitmap myDestBitmap = null;
if (selfieFile.exists()) {
mySrcBitmap = BitmapFactory.decodeFile(selfieFile.getAbsolutePath());
}
if (mySrcBitmap != null) {
// Get info about view to be updated
mImageViewToBeUpdated = (ImageView) params[1];
mImageHeight = mImageViewToBeUpdated.getHeight();
mImageWidth = mImageViewToBeUpdated.getWidth();
if (mySrcBitmap.getWidth() >= mySrcBitmap.getHeight()){
myDestBitmap = Bitmap.createBitmap(
mySrcBitmap,
mySrcBitmap.getWidth()/2 - mySrcBitmap.getHeight()/2,
0,
mySrcBitmap.getHeight(),
mySrcBitmap.getHeight()
);
}else{
myDestBitmap = Bitmap.createBitmap(
mySrcBitmap,
0,
mySrcBitmap.getHeight()/2 - mySrcBitmap.getWidth()/2,
mySrcBitmap.getWidth(),
mySrcBitmap.getWidth()
);
}
mySrcBitmap = Bitmap.createScaledBitmap(myDestBitmap, mImageWidth, mImageHeight, true);
}
return mySrcBitmap;
}
提前感谢您的回答。
【问题讨论】:
标签: android listview asynchronous android-listview android-asynctask