android - 方向更改后未完成的 AsyncTask 中的 View 引用会发生什么情况?

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

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

我有一个属于 GridView 项目的 holder 类,它引用了一个 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;
    }
}

一条评论表明,方向更改后此代码可能存在问题。

场景

  • 网格处于横向模式
  • 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

最佳答案

Since mHolder.mRowImage does not exist any more because orientation change so there should be a crash.

这是不正确的,所有线程都是 GC 根,并且您的 AsyncTask 持有对 View 对象的强引用(它在您的 Holder 中类)并且您的 View 对 Activity/Fragment/等有很强的引用。因此,只要您的 AsyncTask 正在运行,您的 Activity/Fragment/etc 就不会被正确地垃圾收集。它不会导致任何崩溃(因为 View 确实存在)但会发生内存泄漏并且结果将传递给旧的 Activity/Fragment/等。

但是,如果您确保正确取消了 AsyncTask,一切都会好起来的。但是如果你想 100% 确定你应该使用 WeakReferenceBitmapLoaderAsyncTask

中保存你的 Holder

@编辑

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

关于android - 方向更改后未完成的 AsyncTask 中的 View 引用会发生什么情况?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33394184/

相关文章:

android - 膨胀异常 : Binary XML file line #8: Error inflating class ImageView

Android AsyncTask 用于网络目的是个坏主意吗?

java - java.lang.IllegalMonitorStateException 在 udp 网络上的定时发送失败

android-layout - Android 表格布局适配器建议?

android - 如何在Android中使用Spinner实现搜索?

refactoring - 将一系列重复的 View 组件提取到自己的 View 中的最佳方法?

安卓.security.KeyStoreException : Unknown error On a rare number of devices

android - 支持库 AsyncTaskLoader 不支持被取消?

java - Recyclerview 适配器中的空指针异常

android - 如何获取 viewPager 的选定选项卡?