package com.fsck.k9.activity.misc; import android.app.Activity; import android.app.ProgressDialog; import android.content.Context; import android.os.AsyncTask; /** * Extends {@link AsyncTask} with methods to attach and detach an {@link Activity}. * *

* This is necessary to properly handle configuration changes that will restart an activity. *

* Note: * Implementing classes need to make sure they have no reference to the {@code Activity} instance * that created the instance of that class. So if it's implemented as inner class, it needs to be * {@code static}. *

* * @param * see {@link AsyncTask} * @param * see {@link AsyncTask} * @param * see {@link AsyncTask} * * @see #restore(Activity) * @see #retain() */ public abstract class ExtendedAsyncTask extends AsyncTask implements NonConfigurationInstance { protected Activity mActivity; protected Context mContext; protected ProgressDialog mProgressDialog; protected ExtendedAsyncTask(Activity activity) { mActivity = activity; mContext = activity.getApplicationContext(); } /** * Connect this {@link AsyncTask} to a new {@link Activity} instance after the activity * was restarted due to a configuration change. * *

* This also creates a new progress dialog that is bound to the new activity. *

* * @param activity * The new {@code Activity} instance. Never {@code null}. */ @Override public void restore(Activity activity) { mActivity = activity; showProgressDialog(); } /** * Detach this {@link AsyncTask} from the {@link Activity} it was bound to. * *

* This needs to be called when the current activity is being destroyed during an activity * restart due to a configuration change.
* We also have to destroy the progress dialog because it's bound to the activity that's * being destroyed. *

* * @return {@code true} if this instance should be retained; {@code false} otherwise. * * @see Activity#onRetainNonConfigurationInstance() */ @Override public boolean retain() { boolean retain = false; if (mProgressDialog != null) { removeProgressDialog(); retain = true; } mActivity = null; return retain; } /** * Creates a {@link ProgressDialog} that is shown while the background thread is running. * *

* This needs to store a {@code ProgressDialog} instance in {@link #mProgressDialog} or * override {@link #removeProgressDialog()}. *

*/ protected abstract void showProgressDialog(); protected void removeProgressDialog() { mProgressDialog.dismiss(); mProgressDialog = null; } /** * This default implementation only creates a progress dialog. * *

* Important: * Be sure to call {@link #removeProgressDialog()} in {@link AsyncTask#onPostExecute(Object)}. *

*/ @Override protected void onPreExecute() { showProgressDialog(); } }