问题
Note this question was inspired by a comment to https://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 imagemHolder.mRowImage
is updated. SincemHolder.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(..)
thatmHolder.mRowImage
is not valid any more? - Or is there something in Android that protects the
AsyncTask
?
回答1:
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.
来源:https://stackoverflow.com/questions/33394184/what-happens-with-view-references-in-unfinished-asynctask-after-orientation-chan