【问题标题】:What happens with view references in unfinished AsyncTask after orientation change?方向更改后未完成的 AsyncTask 中的视图引用会发生什么情况?
【发布时间】:2015-10-28 14:45:13
【问题描述】:

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

我有一个持有者类,它属于一个 GridView-item 并引用了一个 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

【问题讨论】:

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


    【解决方案1】:

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

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

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

    @编辑

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

    【讨论】:

    • 当前任务取消代码用于取消超出网格视图的图像下载。重新创建带有支架的方向更改 gitem 后。我同意由于这些引用 GridItemView.tag -> Holder.mRowImage -> GridItemView 可能存在内存泄漏。如果我在Holder 中使用WeakReference,则mHolder.mRowImageonPostExecute(..) 中旋转后可能不再有效
    • 确实 mRowImage 在旋转后将无效,这就是为什么有更好的方法在后台线程中工作(例如在屏幕方向更改期间存活并将结果传递给正确的活动的加载程序/片段)。
    猜你喜欢
    • 2014-02-05
    • 2011-02-13
    • 2019-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多