同方向变化后未完成的AsyncTask视图引用会发生什么? [英] What happens with view references in unfinished AsyncTask after orientation change?

查看:186
本文介绍了同方向变化后未完成的AsyncTask视图引用会发生什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请注意这个问题是由以 http://stackoverflow.com/a/33370816/519334 评论启发。

我有属于与参考的GridView项到ImageView的一个holder类

 公共静态类持有人{
    ImageView的mRowImage;
    串mImageUrl;    // neccessary取消未完成的下载
    BitmapLoaderAsyncTask mDownloader;
}

相应GridItemAdapter使用一个的AsyncTask获取图像的的GridItem

 公共类GridItemAdapter延伸BaseAdapter {
    @覆盖
    公共查看getView(INT位置,...){
        ...
        如果(查看== NULL){
            持有人= ...
            ...
        }其他{
            支架=(座)view.getTag();
        }
        ...
        //取消未完成的mDownloader
        如果(holder.mDownloader!= NULL){
            holder.mDownloader.cancel(假);
            holder.mDownloader = NULL;
        }
        holder.mImageUrl = mImageUrls.get(位置);
        holder.mDownloader =新BitmapLoaderAsyncTask()
        holder.mDownloader.execute(保持器);
    }
}静态类BitmapLoaderAsyncTask扩展的AsyncTask<支架,太虚,位图> {
    持有人mHolder;
    保护位图doInBackground(持有人持有...){
        mHolder =持有者[0];
        ...
    }
    保护无效onPostExecute(...){
        mHolder.mDownloader = NULL;
        如果(!isCancelled()){
            this.mHolder.mRowImage.setImageBitmap(图片);
        }
        this.mHolder = NULL;
    }
}

注释建议,有可能与方向改变后,这个code的一个问题。

SZENARIO


  • 电网是在风景 - 模式

  • GridItemAdapter开始BitmapLoaderAsyncTask#1装载Image1.jpg

    • 异步任务有mHolder.mRowImage


  • 从横向网格方向更改为纵向模式

  • BitmapLoaderAsyncTask#1结束,并呼吁 onPostExecute(..)

  • (!)在 onPostExecute(..) mHolder.mRowImage 更新的形象。自 mHolder.mRowImage 不存在了,因为方向的改变所以应该有一个崩溃。

我有<一个href=\"https://github.com/k3b/AndroFotoFinder/blob/FDroid/app/src/main/java/de/k3b/android/androFotoFinder/gallery/cursor/GalleryCursorAdapter.java\"的rel =nofollow的> code类似描述的场景
而到现在为止我HAVN-T有(!)崩溃呢。

我的问题


  • 这是刚刚coincedence,有没有(!)崩溃了吗?

  • 有一个简单的解决方案,在 onPostExecute(..) mHolder.mRowImage 是无效的检查更多?

  • 或者是有什么在Android中,保护的AsyncTask


解决方案

  

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


这是不正确的,所有的线程都GC根,你的的AsyncTask 持有强引用查看对象(这是你的类中),你的查看具有较强的参考活动/片段/等。所以,你的活动/片段/等不能得到妥善的垃圾,只要收集你的的AsyncTask 正在运行。它不会造成任何崩溃(因为做观存在),但内存泄漏会发生和结果将被传递到老年活动/片段/等。

然而,如果你确保的AsyncTask 取消妥善一切都会好的。但是,如果你想成为100%肯定,你应该使用的WeakReference 来抱你在持有人 BitmapLoaderAsyncTask

@edit

你现在的任务取消的方式不正确。取向后改变所有的视图将被再次充气(新活动/片段/等),从而view.getTag总是会导致空。

Note this question was inspired by a comment to http://stackoverflow.com/a/33370816/519334 .

I have a holder class that belongs to a GridView-item with a reference to an ImageView

public static class Holder {
    ImageView mRowImage;
    String mImageUrl;

    // neccessary to cancel unfinished download
    BitmapLoaderAsyncTask mDownloader;
}

The corresponding GridItemAdapter uses an AsyncTask to get the image for the 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;
    }
}

A comment suggested that there might be a problem with this code after orientation change.

Szenario

  • Grid is in Landscape - mode
  • GridItemAdapter starts BitmapLoaderAsyncTask#1 for loading Image1.jpg
    • async task has mHolder.mRowImage
  • Grid orientation changes from Landscape to Portrait mode
  • BitmapLoaderAsyncTask#1 finishes and calls onPostExecute(..)
  • (!!!) In onPostExecute(..) the image mHolder.mRowImage is updated. Since mHolder.mRowImage does not exist any more because orientation change so there should be a crash.

I have code similar to the described scenario and up to now I havn-t had the (!!!) crash yet.

My Question

  • Is this just coincedence that there was no (!!!) crash yet?
  • Is there a simple solution to check in onPostExecute(..) that mHolder.mRowImage is not valid any more?
  • Or is there something in Android that protects the AsyncTask?

解决方案

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

That is not correct, all Threads are GC roots, and your AsyncTask is holding strong reference to View object (it's inside your Holder class) and your View has strong reference to Activity/Fragment/etc. So your Activity/Fragment/etc won't be properly garbage collected as long as your AsyncTask is running. It won't cause any crash (because View do exists) but memory leak will occur and result will be delivered to old Activity/Fragment/etc.

However if you make sure that AsyncTask is cancelled properly everything will be ok. But if you want to be 100% sure you should use WeakReference to hold you Holder class in BitmapLoaderAsyncTask

@edit

The way you do task cancelling now is incorrect. After orientation change all the view will be inflated once again (in new Activity/Fragment/etc), thus view.getTag will always result null.

这篇关于同方向变化后未完成的AsyncTask视图引用会发生什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆