Android 方向更改后,未完成的AsyncTask中的视图引用会发生什么情况?
注意:这个问题的灵感来自对的评论 我有一个holder类,它属于GridView项,引用了ImageViewAndroid 方向更改后,未完成的AsyncTask中的视图引用会发生什么情况?,android,android-asynctask,android-adapter,android-orientation,Android,Android Asynctask,Android Adapter,Android Orientation,注意:这个问题的灵感来自对的评论 我有一个holder类,它属于GridView项,引用了ImageView public static class Holder { ImageView mRowImage; String mImageUrl; // neccessary to cancel unfinished download BitmapLoaderAsyncTask mDownloader; } 相应的GridItemAdapter使用AsyncTas
public static class Holder {
ImageView mRowImage;
String mImageUrl;
// neccessary to cancel unfinished download
BitmapLoaderAsyncTask mDownloader;
}
相应的GridItemAdapter使用AsyncTask获取GridItem的映像
public class GridItemAdapter extends BaseAdapter {
@Override
public View getView(int position, ...) {
...
if (view == null) {
holder = ...
...
} else {
holder = (Holder) view.getTag();
}
...
// cancel unfinished mDownloader
if (holder.mDownloader != null) {
holder.mDownloader.cancel(false);
holder.mDownloader = null;
}
holder.mImageUrl = mImageUrls.get(position);
holder.mDownloader = new BitmapLoaderAsyncTask()
holder.mDownloader.execute(holder);
}
}
static class BitmapLoaderAsyncTask extends AsyncTask<Holder, Void, Bitmap> {
Holder mHolder;
protected Bitmap doInBackground(Holder... holders) {
mHolder = holders[0];
...
}
protected void onPostExecute(...) {
mHolder.mDownloader = null;
if (!isCancelled()) {
this.mHolder.mRowImage.setImageBitmap(image);
}
this.mHolder = null;
}
}
公共类GridItemAdapter扩展了BaseAdapter{
@凌驾
公共视图getView(内部位置,…){
...
如果(视图==null){
持有人=。。。
...
}否则{
holder=(holder)view.getTag();
}
...
//取消未完成的mDownloader
if(holder.mDownloader!=null){
holder.mDownloader.cancel(false);
holder.mDownloader=null;
}
holder.mImageUrl=mImageUrls.get(位置);
holder.mDownloader=新的BitmapLoaderAsyncTask()
holder.mDownloader.execute(holder);
}
}
静态类BitmapLoaderAsyncTask扩展了AsyncTask{
持有人mHolder;
受保护位图背景(支架…支架){
mHolder=持有人[0];
...
}
受保护的void onPostExecute(…){
mHolder.mDownloader=null;
如果(!isCancelled()){
this.mHolder.mRowImage.setImageBitmap(图像);
}
this.mHolder=null;
}
}
一条评论指出,在方向更改后,此代码可能存在问题
塞纳里奥
- 网格处于横向模式
- GridItemAdapter启动BitmapLoaderAsyncTask#1以加载Image1.jpg
- 异步任务具有mHolder.mRowImage
- 栅格方向从横向模式更改为纵向模式
- BitmapLoaderAsyncTask#1完成并调用
onPostExecute(..)
- (!!!)在
中,图像onPostExecute(…)
被更新。因为mHolder.mRowImage
不再存在,因为方向改变了,所以应该会发生崩溃mHolder.mRowImage
- 这仅仅是没有(!!!)崩溃的巧合吗
- 是否有一个简单的解决方案来签入
使onPostExecute(..)
不再有效mHolder.mRowImage
- 或者安卓系统中有什么东西可以保护
异步任务
AsyncTask
持有对View
对象的强引用(它在Holder
类中)而且您的视图
强烈引用了活动/片段/etc。因此,只要您的异步任务
正在运行,您的活动/片段/etc就不会被正确地垃圾收集。它不会导致任何崩溃(因为视图确实存在),但会发生内存泄漏,结果将传递给旧的Activity/Fragment/etc
但是,如果您确保正确取消了AsyncTask
,一切都会正常。但是如果你想100%确定你应该使用WeakReference
在BitmapLoaderAsyncTask
@编辑
您现在执行任务取消的方式不正确。更改方向后,所有视图将再次膨胀(在新活动/片段/etc中),因此view.getTag将始终为空。当前任务取消代码用于取消网格视图外图像的图像下载。方向更改后,将重新创建带支架的项目。我同意这些引用可能会导致内存泄漏
GridItemView.tag
->Holder.mRowImage
->GridItemView
。如果我在Holder
中使用WeakReference
,那么mHolder.mRowImage
在onPostExecute(…)
中旋转后可能不再有效,这是真的mRowImage
在旋转后将无效,这就是为什么有更好的方法在后台线程中工作的原因(类似于在屏幕方向改变期间幸存下来并将结果交付给适当活动/片段的装载机)。