Continuing from AsyncTask usage summary. Interest is how to establish independence between Activity and AsyncTask? The answer is well summarized in the article, “Android AsyncTask はバックグラウンドの処理に集中すべし!”. I will just translate and re-summarize this article. 3 ways will be introduced.
Contents
Advance – implementation framework of AsyncTask
A. Define as inner class of Activity
Most intuitive, easy and faster way is to implement your AsyncTask inside Activity which use it. It is nice choice when CustomAsyncTask is specific (highly dependent on) to the parent Activity.
Mock implementation is like below, here text of mEditText
is updated after AsyncTask’s background process.
public class SomeActivity extends Activity { private static final String TAG = SomeActivity.class.getSimpleName(); private EditText mEditText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mEditText = (EditText) findViewById(R.id.edit_text); (new CustomAsyncTask()).execute(); } public class CustomAsyncTask extends AsyncTask<Void, Void, String> { @Override protected String doInBackground(Void... params) { String result = null; // background process return result; } protected void onPostExecute(String result) { // Update Activity UI here mEditText.setText(result); } } }
The problem is that member of Activity, mEditText
, is used inside onPostExecute()
method of CustomAsyncTask. So this is basically only applicable for this Activity. To separate the work of common AsyncTask part and Activity’s UI update part, we can take following methods. One way is to override methods at Activity, the other way is to implement custom callback.
B. Override UI thread task at Activity side
Consider like this. AsyncTask should concentrate on background task, Activity side will do all UI update task. We can achieve it by overriding UI thread task (onPreExecute, onProgressUpdate and onPostExecute) at Activity.
Mock implementation
public class SomeActivity extends Activity { private static final String TAG = SomeActivity.class.getSimpleName(); private EditText mEditText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mEditText = (EditText) findViewById(R.id.edit_text); new CustomAsyncTask(){ // Override UI thread methods in Activity @Override protected void onPostExecute(String result) { // Update Activity UI here mEditText.setText(result); } }.execute(); } }
public class CustomAsyncTask extends AsyncTask<Void, Void, String> { @Override protected String doInBackground(Void... params) { String result = null; // background process return result; } }
As you can see, CustomAsyncTask only implements doInBackground()
method. All other UI update method is implemented in Activity (caller) side. It is a tricky implementation, but it enables us to divide the role of AsyncTask and Activity.
One concern is it has less encapsulation (basically, Activity side can do any UI update based on the result). No common behavior of onPostExecute()
is implemented in AsyncTask side, This implementaton may differ among Activities.
C. Register callback to invoke Activity method
The last, most organized way to make AsyncTask independent from Activity is to implement callback. We can reduce dependency between Activity and AsyncTask, but you need to take care about designing callback method types.
Callback methods are implemented as interface in below mock implementation.
import android.os.AsyncTask; /** * AsyncTask<Params, Progress, Result> * Params: Input parameter type * - arg of {@link #doInBackground} * * Progress: Progress parameter type * - arg of {@link #onProgressUpdate} * * Result: Return parameter from background process * - return type of {@link #doInBackground} * - arg of {@link #onPostExecute} */ public class CustomAsyncTask extends AsyncTask<Void, Void, String> { private static final String TAG = CustomAsyncTask.class.getSimpleName(); private CustomAsyncTaskCallback mCallback = null; public CustomAsyncTask(CustomAsyncTaskCallback callback) { mCallback = callback; } @Override protected void onPreExecute() { // Initial UI set up here (if necessary) if(mCallback != null){ mCallback.onPreExecute(); } } @Override protected String doInBackground(Void... params) { String result = null; // Implement (maybe long) background process here! return result; } @Override protected void onProgressUpdate(Void... values) { // invoked when publishProgress() is called, } @Override protected void onPostExecute(String result) { // Finally, the result of doInBackground is handled on UI thread here. if(mCallback != null){ mCallback.onPostExecute(result); } } /** Interface for Activity callback */ public interface CustomAsyncTaskCallback { void onPreExecute(); void onPostExecute(String result); /* Add other callback method if necessary */ // void onProgressUpdate(); } }
To use this callbacks at Activity side, Activity can implement this callback interface. Then, we can implement the function of this callback at Activity side to update UI.
public class SomeActivity extends Activity implements CustomAsyncTask.CustomAsyncTaskCallback { private static final String TAG = SomeActivity.class.getSimpleName(); private EditText mEditText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mEditText = (EditText) findViewById(R.id.edit_text); new CustomAsyncTask(this).execute(); } /** CustomAsyncTaskCallback interface implementation */ @Override public void onPreExecute() { // This callback is invoked from CustomAsyncTask.onPreExecute() } /** CustomAsyncTaskCallback interface implementation */ @Override public void onPostExecute(String result) { // This callback is invoked from CustomAsyncTask.onPostExecute() mEditText.setText(result); } }
Summary table
A. Inner class implementation | B. Override UI thread methods | C. Callback implementation | |
Independent from Activity? | – | ✓ | ✓ |
Pros | EasyFast | FasterFlexible | Most organized |
Cons | The AsyncTask is only for parent Activity | Tricky Haphazard | Strict design is neededTroublesome |
Conclusion – which way to use?
- Implementation speed is more important. (First implementation, debugging etc)
- It is ok that the CustomAsyncTask is only for specific Activity
→ A. Implement as inner class of Activity - Personal, small team project.
- Faster, more flexible, unplanned implementation.
→ B. Override UI thread task from Activity side - Official, team project.
- Specification is designed concretely.
→ C. Use callback at Activity side
* This is just a personal opinion. Please find yourself which method to adopt for your project.