方向改变后未完成的AsyncTask中的视图引用会发生什么?

时间:2015-10-28 14:45:14

标签: android android-asynctask android-adapter android-orientation

请注意,此问题的灵感来自对https://stackoverflow.com/a/33370816/519334的评论。

我有一个持有者类,它属于GridView项目,引用了ImageView

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;
    }
}

注释表明在更改方向后,此代码可能存在问题。

SZENARIO

  • 网格处于横向模式
  • GridItemAdapter启动BitmapLoaderAsyncTask#1以加载Image1.jpg
    • 异步任务有mHolder.mRowImage
  • 网格方向从横向模式更改为纵向模式
  • BitmapLoaderAsyncTask#1完成并调用onPostExecute(..)
  • (!!!)在onPostExecute(..)中,图片mHolder.mRowImage已更新。由于mHolder.mRowImage不再存在,因为方向发生变化所以应该会发生崩溃。

我有code similar to the described scenario 直到现在我还没有(!!!)崩溃。

我的问题

  • 这只是说服没有(!!!)崩溃吗?
  • 是否有一个简单的解决方案来检查onPostExecute(..) mHolder.mRowImage是否已无效?
  • Android中是否存在保护AsyncTask
  • 的内容

1 个答案:

答案 0 :(得分:1)

  

由于mHolder.mRowImage不再存在,因为方向   改变所以应该发生崩溃。

这是不正确的,所有主题都是GC根源,而您的AsyncTask强烈引用View对象(它位于Holder类内)和您的{ {1}}强烈引用Activity / Fragment / etc.因此,只要您的View正在运行,您的Activity / Fragment / etc就不会被正确地进行垃圾回收。它不会导致任何崩溃(因为View确实存在),但会发生内存泄漏,结果将传递给旧的Activity / Fragment / etc。

但是,如果您确保AsyncTask被正确取消,一切都会好的。但是,如果你想100%确定你应该使用AsyncTask在[{1}}

中使用WeakReference课程

@edit

现在取消任务的方式不正确。在方向改变之后,所有视图将再次膨胀(在新的Activity / Fragment / etc中),因此view.getTag将始终为null。