0
\$\begingroup\$

I want to use the WeakReference approach to not leak memory with my AsyncTask. I found examples online and on Stackoverflow, but they only get the reference in onPostExecute and I am unsure how to correctly use it in all 3 of the UI methods. My current approach is like this, but I have no clue if I can get rid of some redundancy. Why can't I just call activityReference.get() in the constructor and then only check for null in each of the UI methods? Why do the examples online call get right before using the WeakReference?

private static class ExampleAsyncTask extends AsyncTask<Integer, Integer, String> {
    private WeakReference<MainActivity> activityReference;

    ExampleAsyncTask(MainActivity context) {
        activityReference = new WeakReference<>(context);
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();

        MainActivity activity = activityReference.get();
        if (activity == null || activity.isFinishing()) {
            return;
        }

        activity.progressBar.setVisibility(View.VISIBLE);
    }

    @Override
    protected String doInBackground(Integer... integers) {
        for (int i = 1; i < integers[0]; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            publishProgress((i * 100) / integers[0]);
        }

        return "Finished";
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);

        MainActivity activity = activityReference.get();
        if (activity == null || activity.isFinishing()) {
            return;
        }

        activity.progressBar.setProgress(values[0]);
    }

    @Override
    protected void onPostExecute(String s) {
        super.onPostExecute(s);

        MainActivity activity = activityReference.get();
        if (activity == null || activity.isFinishing()) {
            return;
        }

        activity.progressBar.setProgress(0);
        activity.progressBar.setVisibility(View.INVISIBLE);
        Toast.makeText(activity, s, Toast.LENGTH_SHORT).show();
    }
} 
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

Check for null in WeakReference everytime you need to use it is necessary because the GC process can clear the instance anytime during your work. Besides, onPreExecute, onPostExecute and doInBackground is run in the different thread, there is also some delay when changing thread and the instance may be cleared in between too.

I have a helper method that does the check for null in WeakReference and its instance. Use it if you like:

public <T> T getInstance(WeakReference<T> weakReference) {
    if (weakReference == null || weakReference.get() == null)
        return null;

    // Do more check for your activity if need

    return weakReference.get();
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.