Ideally, I'd like to be able to use AsyncTask.executeOnExecutor()
with a SERIAL_EXECUTOR
, but this is only available for API level 11 or above:
new AsyncTask().executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, params);
To target the Android APIs below level 11, I ended up implementing a custom class which encapsulates an ExecutorService
with a thread pool size of 1. The full code is open-sourced here.
Executors.newFixedThreadPool(int nThreads)
creates a thread pool that reuses a fixed number of threads operating off a shared unbounded queue. At any point, at most nThreads
threads will be active processing tasks. In my case, nThreads
is 1, which means tasks can be queued, but only one task will be executed at any given time.
Here is the code:
public abstract class SerialExecutor {
private final ExecutorService mExecutorService;
public SerialExecutor() {
mExecutorService = Executors.newFixedThreadPool(1);
}
public void queue(Context context, TaskParams params) {
mExecutorService.submit(new SerialTask(context, params));
}
public void stop() {
mExecutorService.shutdown();
}
public abstract void execute(TaskParams params);
public static abstract class TaskParams { }
private class SerialTask implements Runnable {
private final Context mContext;
private final TaskParams mParams;
public SerialTask(Context context, TaskParams params) {
mContext = context;
mParams = params;
}
public void run() {
execute(mParams);
Activity a = (Activity) mContext;
a.runOnUiThread(new OnPostExecute());
}
}
/**
* Used to notify the UI thread
*/
private class OnPostExecute implements Runnable {
public void run() {
}
}
}
This can be extended and used as a serial task executor in an Activity
:
public class MyActivity extends Activity {
private MySerialExecutor mSerialExecutor;
@Override
public void onCreate(Bundle savedInstanceState) {
// ...
mSerialExecutor = new MySerialExecutor();
}
@Override
protected void onDestroy() {
if (mSerialExecutor != null) {
mSerialExecutor.stop();
}
super.onDestroy();
}
public void onTrigger(int param) {
mSerialExecutor.queue(this, new MySerialExecutor.MyParams(param));
}
private static class MySerialExecutor extends SerialExecutor {
public MySerialExecutor() {
super();
}
@Override
public void execute(TaskParams params) {
MyParams myParams = (MyParams) params;
// do something...
}
public static class MyParams extends TaskParams {
// ... params definition
public MyParams(int param) {
// ... params init
}
}
}
}
doInBackground
can be called by different background threads, as per documentation. Since the UI thread can callnew SynchronizedTask()
at any time before a previous one has finished, you can have two or more different interleaving threads executingdoInBackground
at the same time. – NorvinExecutor
which will be used by each Activity to serialize the task execution. – NorvindoInBackgournd()
method in differentAysncTask
instance objects read and write some same variables. This could make error. So I think to synchronize the AysncTask instance object is necessary. – ColladoFroyo
, can it supportSingleThreadExecutor
? – Colladoone thread
running the task(extendsAysncTask
) and that's what it currently does. But for older version API and OS, theasyncTask
run on concurrently.(commonsware.com/blog/2012/04/20/…) Should I addsynchronize
or manage the execution of the thread or justdo something
to prevent the callers call the task concurrently? Thanks. – Collado