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();
}
}
1 Answer 1
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();
}