请注意,此问题的灵感来自对 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% 确定你应该使用 WeakReference
在 BitmapLoaderAsyncTask
Holder
类
@编辑
您现在取消任务的方式不正确。方向更改后,所有 View 将再次膨胀(在新的 Activity/Fragment/等中),因此 view.getTag 将始终为 null。
关于android - 方向更改后未完成的 AsyncTask 中的 View 引用会发生什么情况?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33394184/