Created
December 11, 2012 08:40
-
-
Save brnhffmnn/4257045 to your computer and use it in GitHub Desktop.
An AsyncTask which is able to continue the work and update progress state even during configuration changes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package de.slowpoke; | |
import android.app.Activity; | |
import android.app.ProgressDialog; | |
import android.content.Context; | |
import android.os.AsyncTask; | |
import android.os.Bundle; | |
import android.support.v4.app.FragmentActivity; | |
/** | |
* An {@link AsyncTask} which is able to continue the work and update progress state even during configuration changes | |
* (e.g. orientation change)<br> | |
* <br> | |
* <em>Adapted from <a href="https://github.com/commonsguy/cw-android/blob/master/Rotation/RotationAsync/src/com/commonsware/android/rotation/async/RotationAsync.java">RotationAsync.java</a></em> | |
* | |
* @author github.com/panzerfahrer | |
* @version 1.2 | |
* | |
*/ | |
public abstract class RotationAwareAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> { | |
private boolean isFinished = false; | |
private Result savedResult; | |
private IRotationAwareTaskHolder<Progress> holder; | |
private Bundle lastErrorData; | |
/** | |
* Create a new task. | |
* | |
* @param holder | |
* most likely an {@link Activity} | |
*/ | |
public RotationAwareAsyncTask(IRotationAwareTaskHolder<Progress> holder) { | |
this.holder = holder; | |
} | |
/** | |
* If you override this you must call through to the super implementation | |
* | |
* @see android.os.AsyncTask#onPreExecute() | |
*/ | |
@Override | |
protected void onPreExecute() { | |
super.onPreExecute(); | |
this.holder.onStartRotationAwareTask(); | |
} | |
@Override | |
final protected void onProgressUpdate(Progress... values) { | |
if (holder != null) { | |
holder.onUpdateRotationAwareTaskProgress(onRotationAwareProgressUpdate(values)); | |
} | |
}; | |
/** | |
* Called by {@link AsyncTask#onProgressUpdate(Object...)} as long as the holder is available.<br> | |
* <br> | |
* <em>Override if you need to process the progress value</em> | |
* | |
* @param values | |
* progress update initially from {@link AsyncTask#publishProgress(Progress)} | |
*/ | |
protected Progress[] onRotationAwareProgressUpdate(Progress... values) { | |
return values; | |
} | |
@Override | |
final protected void onPostExecute(Result result) { | |
if (holder != null) { | |
if (!isCancelled()) { | |
onRotationAwarePostExecute(result); | |
} | |
holder.onFinishRotationAwareTask(); | |
} else { | |
this.isFinished = true; | |
this.savedResult = result; | |
} | |
}; | |
/** | |
* Called by {@link AsyncTask#onPostExecute(Object)} as long as the holder is available. If the holder is not | |
* available the result will be cached and this will be invoked right after | |
* {@link #attachAsyncTaskHolder(IRotationAwareTaskHolder)} is called | |
* | |
* @param values | |
*/ | |
abstract protected void onRotationAwarePostExecute(Result values); | |
/** | |
* @return the associated holder or <code>null</code> if a configuration change is just happening | |
*/ | |
protected IRotationAwareTaskHolder<Progress> getHolder() { | |
return this.holder; | |
} | |
/** | |
* Call if the task shall be canceled. | |
*/ | |
abstract public void onCancel(); | |
/** | |
* Notify this task in {@link Activity#onRetainNonConfigurationInstance()} or | |
* {@link FragmentActivity#onRetainCustomNonConfigurationInstance()} that a configuration change is happening and | |
* return this instance. <br> | |
* For example: | |
* | |
* <pre> | |
* public Object onRetainNonConfigurationInstance() { | |
* task.detachHolder(); | |
* return task; | |
* } | |
* </pre> | |
* | |
* The implementation will make sure to release the current holder and to not update progress unless the holder is | |
* set. | |
*/ | |
public void detachAsyncTaskHolder() { | |
this.holder = null; | |
} | |
/** | |
* Use to re-attach the holder after configuration change has happened. Get the task instance (which you previously | |
* returned in {@link Activity#onRetainNonConfigurationInstance()}) from | |
* {@link Activity#getLastNonConfigurationInstance()} or | |
* {@link FragmentActivity#getLastCustomNonConfigurationInstance()} in {@link Activity#onCreate(Bundle)} For | |
* example: | |
* | |
* <pre> | |
* protected void onCreate(Bundle savedInstanceState) { | |
* task = (RotationAwareAsyncTask) getLastNonConfigurationInstance(); | |
* | |
* if (task == null) { | |
* task = new RotationAwareAsyncTask(this); | |
* } else { | |
* task.attachHolder(this); | |
* } | |
* } | |
* </pre> | |
* | |
* @param holder | |
*/ | |
public void attachAsyncTaskHolder(IRotationAwareTaskHolder<Progress> holder) { | |
this.holder = holder; | |
if (this.isFinished) { | |
onRotationAwarePostExecute(this.savedResult); | |
holder.onFinishRotationAwareTask(); | |
} | |
} | |
/** | |
* Interface for the {@link RotationAwareAsyncTask} to publish progress updates. | |
* | |
* @author brho | |
* @version 1.1 | |
*/ | |
public static interface IRotationAwareTaskHolder<Progress> { | |
public static final String ROTATION_AWARE_TASK_ERROR_TITLE = "title"; | |
public static final String ROTATION_AWARE_TASK_ERROR_MESSAGE = "message"; | |
/** | |
* Invoked by the {@link RotationAwareAsyncTask} to publish progress updates | |
* | |
* @param progress | |
* some type of progress status (most likely a <code>String</code> or <code>int</code>) which can be | |
* used to update a {@link ProgressDialog} or similar | |
*/ | |
public void onUpdateRotationAwareTaskProgress(Progress... progress); | |
/** | |
* Invoked by the {@link RotationAwareAsyncTask} to notify that the work has been started | |
*/ | |
public void onStartRotationAwareTask(); | |
/** | |
* Invoked by the {@link RotationAwareAsyncTask} to notify that the work has been finished | |
*/ | |
public void onFinishRotationAwareTask(); | |
/** | |
* Invoked when an error occurred, giving the chance to display an error dialog. Mind that this method is not | |
* called from the UI thread, so you need to take care which code of yours needs to run on the UI thread. | |
* | |
* @param data | |
* a {@link Bundle} of data to be handed through. You might want to use one of the predefined keys. | |
*/ | |
public void onShowRotationAwareTaskError(Bundle data); | |
/** | |
* @return the {@link Context} of the implementing instance (try not to return the {@link Activity} itself) | |
*/ | |
public Context getContext(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment