Search code examples
androidandroid-asynctaskweak-references

How to get WeakReference in doInBackground() of AsyncTask


I have a class named RetrieveCoverImageTask. It retrieves the actual cover image from the URL in a Track instance:

private class RetrieveCoverImageTask extends AsyncTask<Track, Void, Void> {

    private WeakReference<Context> context;

    RetrieveCoverImageTask(Context context) {
        this.context = new WeakReference<>(context);
    }

    // V1
    @Override
    protected Void doInBackground(Track... tracks) {
        Context context = this.context.get();
        if (context != null) {
            for (Track track : tracks) {
                try {
                    Bitmap bmp = Picasso.with(context).load(track.getCoverUrl()).get();
                    if (bmp != null) {
                        ByteArrayOutputStream stream = new ByteArrayOutputStream();
                        bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
                        track.setCoverImage(stream.toByteArray());
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    // V2
    @Override
    protected Void doInBackground(Track... tracks) {
        for (Track track : tracks) {
            try {
                Context context = this.context.get();
                if (context != null) {
                    Bitmap bmp = Picasso.with(context).load(track.getCoverUrl()).get();
                    if (bmp != null) {
                        ByteArrayOutputStream stream = new ByteArrayOutputStream();
                        bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
                        track.setCoverImage(stream.toByteArray());
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
}

An example call from an Activity is as below:

new RetrieveCoverImageTask(context).execute(track1, track2, track3);

First, I did V1. Then, I thought that the image retrieval with Picasso takes time and the calling Activity may become null in the meanwhile, therefore, I have to get context at the beginning of each iteration of the for loop. That's how I implemented V2.

Which version of doInBackground() is efficient and error-resistant? V1 or V2?


Solution

  • Efficiency is probably not the biggest issue here. V2 is safer, but the whole thing is not very "elegant". It would be much easier to set something up with RxJava. You would not need WeakReferences. The key would be to dispose of your subscription when the context becomes invalid (e.g. onDestroy()) and you would save the check for null.

    Also you might want to use an approach to getting the bmp that does not involve picasso and thus does not require context. Or you use the application context which exists as long as your application is running, so you do not need the null check