reference

https://www.baidu.com/link?url=QNRznJEBT25k0bpgVD3bOniOia2W85eiPIWrS93YFknyrHoFDGrJVtoax2ZYpiiErtRW7VD-sNEgCRNespIhSK&wd =&eqid=9a27957100030dcd000000065aac77c0

https://www.jianshu.com/p/79cc3c5fc9a3

http://blog.csdn.net/majihua817/article/details/51658465

The following usage and source code analysis is based on Android-27 (version android 8.1.0)

Summary of main points:

1. All asynctasks of a process are not executed in parallel by default. Generally, the default asynctasks executed using execute are executed in a queue and in sequence, and only one AsyncTask will be executed at the same time.

Executor exec,Params… Params) according to the effect of the incoming thread pool, can achieve the effect of multiple AsyncTask asynchronous execution at the same time;

3. Common callback methods include onPreExecute(), doInBackground(Params… Params), onProgressUpdate (Progress… Values), onPostExecute (Result Result)

  • A. Run onPreExecute -> doInBackground- > (onProgressUpdate)->onPostExecute

  • B. OnPreExecute: Runs in the UI thread when the code executes asynctask.execute (Params… Params) will be called, generally can be used for some initialization operations on the interface, such as pop-up download dialog box;

  • C. doInBackground: non-UI threads run in the background to process time-consuming tasks, such as downloading, data processing, etc.

  • D. onProgressUpdate: runs in the UI thread, which can be used to process some operations related to progress update on the interface; OnProgressUpdate can be triggered by calling publishProgress in doInBackground;

  • E. OnPreExecute can also trigger onProgressUpdate with publishProgress, but both are UI threads.

  • F. Notice that publishProgress is also an onProgressUpdate that is triggered by the handler that sends the message. Note that doInBackground does not block until the onProgressUpdate completes

  • G. OnPostExecute: runs in the UI thread, which can be used to prompt the interface to complete the operation, and is called after the doInBackground is completed and the return is used.

  • The @mainThread and @workerThread thread annotations are available in the source code for these important callback methods. However, this annotation is mainly used for IDE compilation to check for errors. Execute and other methods can still be called in child threads. Of course, onPreExecute can’t handle the UI at this point, otherwise it will throw an exception; However, it is recommended that the invocation be consistent with the annotations

4. An AsyncTask that has been executed once or is being executed cannot be executed again through execute or executeOnExecutor

AsyncTask asynctask. THREAD_POOL_EXECUTOR: AsyncTask asynctask. THREAD_POOL_EXECUTOR: AsyncTask asynctask. THREAD_POOL_EXECUTOR: AsyncTask asynctask. THREAD_POOL_EXECUTOR: AsyncTask asynctask. THREAD_POOL_EXECUTOR: AsyncTask asynctask. THREAD_POOL_EXECUTOR: AsyncTask asyncTask. THREAD_POOL_EXECUTOR

Private static final int CPU_COUNT = Runtime.getruntime (). AvailableProcessors (); private static final int CPU_COUNT = runtime.getruntime (). Private static final int CORE_POOL_SIZE = math.max (2, math.min (CPU_COUNT - 1, 4)); 9 private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1; Private static final int KEEP_ALIVE_SECONDS = 30; Private static final BlockingQueue<Runnable> sPoolWorkQueue =new LinkedBlockingQueue<Runnable>(128); ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory); threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
Copy the code

(Assuming that the number of terminal cpus is 4) Because the maximum number of concurrent threads running in the thread pool is 9 and the maximum waiting queue is 128, if the doInBackground of each Asynctask takes a long time, One-time add more than 9 + 128 = 137 task (such as listview in a one-off creation), it will cause abnormal Java util. Concurrent. RejectedExecutionException

6. With execute, there is no queue cache (no size limit, unless memory explodes) and the task is executed sequentially, so there is no case that tasks in the thread pool exceed the size

7. The AsyncTaskd cancel method simply changes the flag bit to true and uses Thread.interrupt to interrupt the Thread execution. This does not guarantee that the execution will stop immediately. Therefore, isCancelled can be used in doInBackground to determine whether the task has been cancelled

The point to explain

(from the resources https://www.jianshu.com/p/79cc3c5fc9a3)

When Android 1.5 was introduced, AsyncTask execute was executed serially; In Android 1.6 and up until Android 2.3.2, this was changed to parallel execution. The thread pool for executing tasks is THREAD_POOL_EXECUTOR, so all asynctasks are executed in parallel within a process. But after Android 3.0, if you use the execute function to execute asynctasks directly, the tasks are executed sequentially. So here’s the takeaway: Android 3.0 and beyond, AsyncTasks don’t run in parallel by default.

Since asynctasks of the same process are all in the same thread pool, if the default is parallel, multiple threads will execute doInBackground operations in multiple tasks at the same time, and doInBackground will access and modify the same resources, so the problem of resource synchronization is often ignored. AsyncTask that uses execute defaults to serial execution for this reason.

If the resource synchronization problem is handled, you can use executeOnExecutor to pass in the appropriate thread pool to achieve the effect of AsyncTask execution in parallel.

Summary of advantages and disadvantages

Advantages:

  • 1. After encapsulation, a simple switch between the sub-thread and THE UI thread is realized, which saves the user the tedious operation of updating the UI interface by the sub-thread

Shortcomings (see http://blog.csdn.net/goodlixueyong/article/details/45895997) :

  • 1. Pay attention to serial execution or parallel execution. 1.5 indicates serial execution, 1.6 to 2.3.2 indicates parallel execution, and 3.0 indicates serial execution and parallel execution if executeOnExecutor is used.

  • 2. Serial, in fact, mainly refers to the operation in doInBackground method. In serial mode, the next asyncTask will not be triggered until the execution of onPostExecute in the task is completed, and the next AsyncTask will be triggered as long as the execution of doInBackground is completed

  • If the activity is a non-static internal asyncTask subclass, it implicitly holds a reference to the activity. Stop asyncTask before the activity is destroyed. Otherwise, the background thread will keep running, resulting in memory leaks, and the view may not exist when you want to update the UI, resulting in exceptions;

  • 4. If the activity is recreated due to screen recreation or is terminated by a background exception, the previously running AsyncTask will still hold a reference to the previous activity. Updating the view on this invalid reference requires attention to the validity of the view

  • 5. When executing in parallel, consider the size of tasks that can be handled by the thread pool

Method of use

Declare MyAsyncTask inheritance and implement asyncTask-related callbacks:

    public class MyAsyncTask extends AsyncTask<String, Integer, Boolean>{
        String TAG="MyAsyncTask"; public MyAsyncTask(String tag) { super(); this.TAG=tag; } / /doThe UI thread is called before InBackground starts and can be used for initialization operations on the interface, such as popup the download dialog @override protected voidonPreExecute() {
            Log.d(TAG,"onPreExecute "+Thread.currentThread());
            Toast.makeText(context,"onPreExecute",Toast.LENGTH_SHORT).show(); } // For background tasks, non-UI threads, for time-consuming tasks, downloads, data processing, etcdoInBackground(String... params) {
            Log.d(TAG,"doInBackground "+Thread.currentThread());
            int count = params.length;
            for(int i=0; i<count; // Call asynctask.cancel () to stop an AsyncTask directly. // Call asynctask.cancel () to stop an AsyncTask directlydoInBackground onProgressUpdate/onPreExecute manual judgment about this flagif(isCancelled()){
                    return false
                }
                String p = params[i];
                Log.d(TAG,"doInBackground:"+p);
                publishProgress(i);
            }
            return true; } // When the background taskdoInBackground calls publishProgress(Progress...) @override protected void onProgressUpdate(Integer... values) { Log.d(TAG,"onProgressUpdate:"+values[0]+""+Thread.currentThread());
            Toast.makeText(context,"onProgressUpdate:"+values[0],Toast.LENGTH_SHORT).show(); } // When the background taskdoInBackground completes and passesreturn@override protected void onPostExecute(Boolean aBoolean) {log. d(TAG,"onPostExecute:"+aBoolean+""+Thread.currentThread());
            Toast.makeText(context,"onPostExecute",Toast.LENGTH_SHORT).show(); } // The AsyncTaskd cancel method simply changes the flag bit totrueFinally, thread.interrupt is used to interrupt Thread execution, but this is not guaranteed to stop execution immediatelydoIsCancelled is used in InBackground to determine whether the task has been cancelled. @override protected void onCancelled(Boolean aBoolean) {log. d(TAG,"onCancelled:"+aBoolean+""+Thread.currentThread()); }}Copy the code

Create related instances and execute AsyncTask:

Test 1: Common use

    Log.d(TAG,"btn1 start");
     MyAsyncTask myAsyncTask =new MyAsyncTask("task1"); // Create a subclass of AsyncTask myAsynctask.execute (Parameters of "1"."Parameter 2"); // start log.d (TAG,"btn1 end"); ** : btn1 start onPreExecute Thread[main,5,maindoInBackground Thread[AsyncTask # 1, 5, the main]
    do1 InBackground: parameterdoInBackground: parameter 2 //doAfter InBackground calls publishProgress, onProgressUpdate is triggered by the handler, anddoOnProgressUpdate :0 Thread[main,5,main] onProgressUpdate:1 Thread[main,5,main] onPostExecute:trueThread[main,5,main] // Called when all operations are completeCopy the code

Test 2: Multiple AsyncTasks execute serially using validation

    Log.d(TAG,"btn1 start");
    MyAsyncTask myAsyncTask =new MyAsyncTask("task1");
    MyAsyncTask myAsyncTask2 =new MyAsyncTask("task2");
    myAsyncTask.execute(Parameters of "1"."Parameter 2");
    myAsyncTask2.execute(Parameters of "1"."Parameter 2");
    Log.d(TAG,"btn1 end"); Task1: onPreExecute Thread[main,5,main] task2: onPreExecute Thread[main,5,main] task2: onPreExecute Thread[main,5,main] btn1 end task1:doInBackground Thread[AsyncTask #1,5,main] //doInBackground is executed sequentially
    task1: doInBackground: Parameter 1 Task1:doInBackground: Parameter 2 Task2:doInBackground Thread[AsyncTask # 2, 5, the main]
    task2: doInBackground: Parameter 1 Task2:doInBackground: arguments 2 //onProgressUpdate and onProgressUpdate are also executed sequentiallydoTask1: onProgressUpdate:0 Thread[main,5,main] task1: onProgressUpdate:1 Thread[main,5,main] task1: onPostExecute:true  Thread[main,5,main]
    task2: onProgressUpdate:0  Thread[main,5,main]
    task2: onProgressUpdate:1  Thread[main,5,main]
    task2: onPostExecute:true  Thread[main,5,main]
Copy the code

Test 3: Parallel execution:

MyAsyncTask myAsyncTask =new MyAsyncTask("task1");
    MyAsyncTask myAsyncTask2 =new MyAsyncTask("task2");
    myAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,Parameters of "1"."Parameter 2");
    myAsyncTask2.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,Parameters of "1"."Parameter 2"); Log output (doBtn1 start task1: onPreExecute Thread[main,5,main] task2: OnPreExecute Thread[main,5,main] // Task1 and task2doTask1:doInBackground Thread[AsyncTask # 1, 5, the main]
    task1: doInBackground: Parameter 1 Task2:doInBackground Thread[AsyncTask # 2, 5, the main]
    task2: doBtn1 end task1: onProgressUpdate:0 Thread[main,5,main] task2: onProgressUpdate:0 Thread[main,5,main] task1:doInBackground: Parameter 2 Task2:doTask1: onProgressUpdate:1 Thread[main,5,main] Task2: onProgressUpdate:1 Thread[main,5,main] task1: onProgressUpdate:1 Thread[main,5,main] task1: onPostExecute:true  Thread[main,5,main]
    task2: onPostExecute:true  Thread[main,5,main]
Copy the code

It can be seen from the test that onPreExecute is executed immediately after the respective AsyncTask calls execute. Subsequent source code analysis can know that onPreExecute is not triggered by handler, otherwise it may be different from doInBackground execution timing.

Test 2: From the subsequent source analysis, we can know that the doInBackground part of the AsyncTask triggered by execute is actually executed in a queue in the thread pool, so only one task’s doInBackground is executed. Get the doInBackground of the next task to execute;

From the source analysis can know that onProgressUpdate, onPostExecute is controlled by the handler message, itself is executed in order; Multiple AsyncTask lifecycle steps are interspersed;

According to the log output and source code principle, the sequential execution of AsyncTask has certain shortcomings. OnPreExecute -> doInBackground- > (onProgressUpdate)->onPostExecute does not wait for the next AsyncTask to complete its life cycle;

Test 3: Verifies the effect of parallel execution by the execution thread pool


Source code analysis

The AsyncTask entry function to start executing work is asynctask.execute, so start with this methodCopy the code

AsyncTask source

The execute function

@MainThread public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); } the annotation also indicates that this method needs to run on the UI thread. Why? This is problem number one; Execute triggers the use of the default thread pool SerialExecutor sDefaultExecutor. This thread pool actually controls a queue and saves tasks to be executed in sequence. If you want to execute AsyncTask concurrently, you can simply pass in the appropriate thread pool using the executeOnExecutor method. Then look at what the invoked executeOnExecutor doesCopy the code
ExecuteOnExecutor function
@MainThread public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params) { if (mStatus ! = Status.PENDING) { switch (mStatus) { case RUNNING: throw new IllegalStateException("Cannot execute task:" + " the task is already running."); case FINISHED: throw new IllegalStateException("Cannot execute task:" + " the task has already been executed " + "(a task can be executed only once)"); } } mStatus = Status.RUNNING; onPreExecute(); mWorker.mParams = params; exec.execute(mFuture); return this; }Copy the code
  • If the AsyncTask has already run or is currently running, an exception will be thrown. Each AsyncTask can only call executeOnExecutor directly or indirectly once.

  • Status If the AsyncTask is in the PENDING Status status. PENDING, the Status is identified as status. RUNNING.

  • Notice that the onPreExecute() method, which is used to initialize the preparation of the UI control, is immediately followed; This illustrates the first two questions:

    • The onPreExecute() method is executed immediately after the execute() method is called.
    • Execute() is called in a non-UI thread, so onPreExecute() is executed in a non-UI thread. This causes an exception to update the UI. Execute() or executeOnExecutor is executed in the UI thread.
    • 3. Although annotations and source code comments require that execute() or executeOnExecutor be executed on the UI thread, it is possible to execute in child threads if you do not override onPreExecute() to perform UI operations (which default is null). It is strongly recommended that the thread of execution be consistent with the annotations
    mWorker.mParams = params;
    exec.execute(mFuture);
Copy the code

It then assigns the params parameter passed to mworker.mparams (which is then passed to doInBackground for processing) and calls the thread pool exec to handle the mFuture;

The thread pool SerialExecutor is passed in to the thread pool exec

    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
Copy the code

For the thread pool SerialExecutor

  • SERIAL_EXECUTOR is static by definition, that is, shared by the same process.
  • SERIAL_EXECUTOR is used to maintain the asyncTask queue, which executes tasks in a first-in, first-out order to THREAD_POOL_EXECUTOR
  • THREAD_POOL_EXECUTOR is also static, and one task is executed before the next one is processed;
  • Therefore, if multiple AsyncTasks are created and executed using execute, SERIAL_EXECUTOR is queued for execution by default. Only one AsyncTask is being executed at a time.
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
// We want at least 2 threads and at most 4 threads inthe core pool, // preferring to have 1 less than the CPU count to avoid saturating // the CPU with background work private static final  int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4)); private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1; private static final int KEEP_ALIVE_SECONDS = 30; private static final ThreadFactory sThreadFactory = newThreadFactory() {
    private final AtomicInteger mCount = new AtomicInteger(1);

    public Thread newThread(Runnable r) {
        return new Thread(r, "AsyncTask #"+ mCount.getAndIncrement()); }}; Asynctasks share public static final Executor THREAD_POOL_EXECUTOR; asyncTasks share static final Executor THREAD_POOL_EXECUTOR; static { ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory); threadPoolExecutor.allowCoreThreadTimeOut(true);
    THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
    
private static class SerialExecutor implements Executor {
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;

        public synchronized void execute(final Runnable r) {
            mTasks.offer(new Runnable() {
                public void run() { try { r.run(); // Call FutureTask mFuture.run()} finally {scheduleNext(); }}});if (mActive == null) {
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext() {
            if((mActive = mTasks.poll()) ! THREAD_POOL_EXECUTOR (mActive); = null) {THREAD_POOL_EXECUTOR (mActive); }}}Copy the code

As you can see, the SerialExecutor will add a task to the queue ArrayDeque (exec. Execute (mFuture)) after execute is called. Execute is passed in as mFuture, an instance of the FutureTask class that implements the Runnable interface. SerialExecutor’s primary role is actually to maintain a queue of tasks, and to take them out in sequence to THREAD_POOL_EXECUTOR, the thread pool that actually executes them

ScheduleNext is called to take a task from the queue to thread pool THREAD_POOL_EXECUTOR for execution (on a first-in-first-out basis) :

public void run() { try { r.run(); // Call FutureTask mFuture.run()} finally {scheduleNext(); // After the execution, get the next task for processing}}Copy the code

The incoming mFuture.run() method is executed, and the next AsyncTask task is fetched and executed by calling scheduleNext again. Let’s look at what the futureTask.run () method does

FutureTask class

// The connection between mWorker and mFuture is made public in the constructor when AsyncTask is created FutureTask(Callable<V> callable) { if (callable == null) throw new NullPointerException(); this.callable = callable; this.state = NEW; Public void run() {if (state! = NEW || ! U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread())) return; try { Callable<V> c = callable; if (c ! = null && state == NEW) { V result; boolean ran; try { result = c.call(); // Call mWorker's call method ran = true; } catch (Throwable ex) { result = null; ran = false; setException(ex); } if (ran) set(result); } } finally { // runner must be non-null until state is settled to // prevent concurrent calls to run() runner = null; // state must be re-read after nulling runner to prevent // leaked interrupts int s = state; if (s >= INTERRUPTING) handlePossibleCancellationInterrupt(s); }}Copy the code

The mfuture.run () method in THREAD_POOL_EXECUTOR actually calls result = c.call(), the WorkerRunnable object mworker.call () of the class that implements Callable;

The creation and association of WorkerRunnable object mWorker and FutureTask object mFuture are located in the AsyncTask constructor.

AsyncTask constructor

Private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR; private static volatile sDefaultExecutor = SERIAL_EXECUTOR; Private static InternalHandler sHandler; private static InternalHandler sHandler; private final WorkerRunnable<Params, Result> mWorker; private final FutureTask<Result> mFuture; private final Handler mHandler; /** * Creates a new asynchronous task. This constructor must be invoked on the UI thread. */ publicAsyncTask() { this((Looper) null); } /** * Creates a new asynchronous task. This constructor must be invoked on the UI thread. * * @hide */ public AsyncTask(@Nullable Handler handler) { this(handler ! = null ? handler.getLooper() : null); } /** * Creates a new asynchronous task. This constructor must be invoked on the UI thread. * * @hide */ public AsyncTask(@Nullable Looper callbackLooper) { mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper() ? getMainHandler() : new Handler(callbackLooper); mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { mTaskInvoked.set(true);
                Result result = null;
                try {
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    //noinspection unchecked
                    result = doInBackground(mParams); // Final execution in the thread pooldoInBackground
                    Binder.flushPendingCommands();
                } catch (Throwable tr) {
                    mCancelled.set(true);
                    throw tr;
                } finally {
                    postResult(result);
                }
                returnresult; }}; mFuture = new FutureTask<Result>(mWorker) { @Override protected voiddone() {
                try {
                    postResultIfNotInvoked(get());
                } catch (InterruptedException e) {
                    android.util.Log.w(LOG_TAG, e);
                } catch (ExecutionException e) {
                    throw new RuntimeException("An error occurred while executing doInBackground()", e.getCause()); } catch (CancellationException e) { postResultIfNotInvoked(null); }}}; }Copy the code

As you can see above, the default constructor is executed

Public AsyncTask(@nullable Looper callbackLooper) {mHandler = getMainHandler();Copy the code
MFuture = new FutureTask<Result>(mWorker);Copy the code

Mfuture.run () from THREAD_POOL_EXECUTOR is executed to mworker.call () :

    try {
            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            //noinspection unchecked
            result = doInBackground(mParams); // Final execution in the thread pooldoInBackground
            Binder.flushPendingCommands();
        } catch (Throwable tr) {
            mCancelled.set(true);
            throw tr;
        } finally {
            postResult(result);
        }
Copy the code

After doInBackground(mParams) is executed, postResult(result) sends the result through the hander and finally triggers the onPostExecute callback in the handler’s UI thread.

PostResult function

private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }
Copy the code
Use handler to send the message that the processing is finishedCopy the code

GetMainHandler function

private static Handler getMainHandler() { synchronized (AsyncTask.class) { if (sHandler == null) { sHandler = new InternalHandler(Looper.getMainLooper()); } return sHandler; }}Copy the code

This method simply creates a handler that runs on the UI thread via looper.getMainLooper (). Note that sHandler is static, meaning that all asyncTasks of a process share a handler to process messages.

InternalHandler class and finish method

private static class InternalHandler extends Handler {
        public InternalHandler(Looper looper) {
            super(looper);
        }
    
        @SuppressWarnings({"unchecked"."RawUseOfParameterizedType"}) @Override public void handleMessage(Message msg) { AsyncTaskResult<? > result = (AsyncTaskResult<? >) msg.obj; Switch (msg.what) {// The onPostExecute method is called after receiving the message and executing finish in the UI thread callbackcase MESSAGE_POST_RESULT:
                    // There is only one result
                    result.mTask.finish(result.mData[0]);
                    break; // Receives the message and executes the onProgressUpdate method in the UI thread callbackcase MESSAGE_POST_PROGRESS:    
                    result.mTask.onProgressUpdate(result.mData);
                    break; }}}Copy the code
  • This handler is used to execute onProgressUpdate on the UI thread after receiving MESSAGE_POST_PROGRESS or after receiving MESSAGE_POST_RESULT. Finally in the UI thread execution onPostExecute/onCancelled method,

  • The two important AsyncTask methods onProgressUpdate and onPostExecute are executed by this handler.

    private void finish(Result result) {
        if(isCancelled()) {// onCancelled onCancelled(result) will be triggered if asynctask.cancle () has been called before; }else{// Otherwise onPostExecute onPostExecute(result) is triggered; } mStatus = Status.FINISHED; }Copy the code

Source summary

  • 1.AsyncTask has two static thread pools SerialExecutor, ThreadPoolExecutor, and a static UI thread handler
SerialExecutor implements Executor : sDefaultExecutor ThreadPoolExecutor : THREAD_POOL_EXECUTOR: All asyncTasks started with execute are queued in order in the processCopy the code
  • 2.AsyncTask constructor initializes handler, WorkerRunnable mWorker, FutureTask mFuture, and associates mWorker with mFuture:
mWorker = new WorkerRunnable<Params, Result>(){.. }.. mFuture = new FutureTask<Result>(mWorker) {.. }..Copy the code
  • 3. Execute:

    • ExecuteOnExecutor () is called and SerialExecutor is passed
    • Execute onPreExecute in executeOnExecutor() and pass the mFuture to SerialExecutor for queuing
    • SerialExecutor fetches tasks in a first-in, first-out order for ThreadPoolExecutor to process using the mFuture.run() method that actually executes to the doInBackground method inside mworker.call (). After the execution is complete, the onPostExecute method is triggered by handler.
  • OnProgressUpdate is triggered by handler if publishProgress is called in the process;

  • If asyncTask is executed in parallel, instead of execute, execute is passed directly to the appropriate thread pool using executeOnExecutor, skipping the SerialExecutor queueing step.