AsyncTask usage and source code analysis

This article is rewritten from: Android multithreading: the principle and source code analysis of AsyncTask https://www.jianshu.com/p/37502bbbb25a

Basic knowledge: see: xxxx / / you must understand the label & futuretask first

3 compound use of AsyncTask: use and Implementation (based on futuretask Implementation)

The principle of AsyncTask is that doInBackground is a new sub thread implementation. For others, such as new task, the processing result is run in the main thread
AsyncTask usage instance
AsyncTask source code analysis: process; Create a workthread inside doInBackground to execute, and post the result to the UI thread

AsyncTask is a function suite. You need to write steps, sequence and main function descriptions

  • Create an instance object of WorkerRunnable class & copy the call() method
  • Create an instance object of FutureTask class & copy {done()

Use: step1: to create the basic implementation of Asynctask subclass

  private class MyTask extends AsyncTask<Params, Progress, Result> {
        ....
      protected void onPreExecute() {...//Actions before executing thread tasks}
      protected String doInBackground(String... params) {
			...// Custom thread tasks Receive input parameters, perform time-consuming operations in the task, and return the results of thread task execution    
             publishProgress(count);//publishProgress() can be called to display the progress, after which onProgressUpdate() will be executed
         }
      protected void onProgressUpdate(Integer... progresses) {...//Displays the progress of thread task execution in the main thread}     
      protected void onPostExecute(String result) {...// UI action}
      protected void onCancelled() {...}
  }

Step 2: create an instance object of AsyncTask subclass (i.e. task instance)

MyTask mTask = new MyTask();

step3: manually call execute(Params... params)

  mTask.execute();
  • AsyncTask # core & common methods are as follows:

  • The execution sequence of the method is as follows

Use flow chart

4. Combined use of thread pool

android thread pool is different from C + +. android thread pool uses ThreadPoolExecutor, and can only pass in runnable or callable class and its subclasses, not thread class
The use method of C + + thread pool is to directly pass in the object, and then execute the run function of the object

Executor threadPool = new ThreadPoolExecutor(...);
threadPool.execute(ThreadTask);
public class ThreadTask implements Runnable{    
    public void run() {
          ... // Thread execution task
    }

Source code analysis:

AsyncTask constructor: the callable & futuretask object is created internally

  public AsyncTask() {
         Callable mWorker = new WorkerRunnable<Params, Result>() {...};
         FutureTask mFuture = new FutureTask<Result>(mWorker) ;
  }

1) resolution of the callable function WorkerRunnable in the constructor: callable class (call -- > doinbackground -- > postresult -- > internalhandler (sendtotarget -- handlemessage))

  • AsyncTask's constructor * / / / focuses on creating and implementing the child thread callable class: implementing time-consuming operations & sending result s to the main function interface
  • The WorkerRunnable class is the constructor of callable
  • Handler mechanism handler(InternalHandler) sends a message in the main thread*/
  • Handler class definition and handle message*/
/*1 AsyncTask Constructor for*///Focus on the creation and implementation of sub thread callable class: realize time-consuming operation & send the result to the main function interface
    public AsyncTask() {
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                Result result = null;
                try {  
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);//Set thread priority       
                    result = doInBackground(mParams);//Execute asynchronous operation = time-consuming operation / / that is, the time-consuming task of replication in the process
                }  finally {         
                    postResult(result); // Send the result of the asynchronous operation to the main thread / / to update the UI
                }
                return result;
            }
        };
        .....// ellipsis
    }
//2. The workerrunnable class is the constructor of callable
  private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
        // Callable here is also a task;
        // Difference from Runnable: callable < T > has return value = its generic type
        Params[] mParams;
    }

2) The handler mechanism is encapsulated inside

/*3 handler Mechanism handler(InternalHandler) sends a message in the main thread*/
   private Result postResult(Result result) {
        //Important: getHandler() gets the handler object Presumably, it is new InternalHandler     
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));// Create Handler object - > > from InternalHandler class - > > analysis 2   
        message.sendToTarget();// Send message to Handler
        return result;
    }
/*4 handler Class definition and handle message mechanism*/
    private static class InternalHandler extends Handler {
        public InternalHandler() {// Constructor
            super(Looper.getMainLooper());// The Looper() of the main thread is obtained / / so the instance creation & execute () of AsyncTask must be used in the main thread   
        }
        public void handleMessage(Message msg) {
            AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
            switch (msg.what) {
                case MESSAGE_POST_RESULT://Pass the result to the main thread through the Handler
                    result.mTask.finish(result.mData[0]);
                    break;
                // be
                case MESSAGE_POST_PROGRESS://Callback onProgressUpdate() to inform the main thread of the update progress
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }
/*Business logic implementation body */
  private void finish(Result result) {
            if (isCancelled()) {//1. Operation when canceling a task
                onCancelled(result);
            } else {
                onPostExecute(result);//2 update UI operation
            }      
            mStatus = Status.FINISHED;//Note: whether AsyncTask is cancelled or not, the status of AsyncTask will be changed to: FINISHED
        }

3) Create futuretask object

Futureask is just some exception handling;

//1 initialize FutureTask variable = 1 FutureTask - > > analysis 2
        mFuture = new FutureTask<Result>(mWorker) {
            // Introduction to done (): the calling method after the Callable in FutureTask is executed
            // Function: review the call of the task and pass the result of the task not called to the UI thread through InternalHandler
            protected void done() {
                try {
                    postResultIfNotInvoked(get());// After executing the task, check and send out the Result that has not been called
                }
            }
        };
/2 *FutureTask Class constructor
  * Definition: packaging class of 1 packaging task
  * Note: internal Callable<T> ,Added some status identifiers & operation Callable<T>Interface of*/
  public FutureTask(Callable<V> callable) {
        this.callable = callable;
        this.state = NEW;      
    }
/*3 The result is passed to the UI thread through the InternalHandler  */
  private void postResultIfNotInvoked()(Result result) {    
        final boolean wasTaskInvoked = mTaskInvoked.get();// Get task tag
        // If the task is not executed, the result of the task that is not called is passed to the UI thread through the InternalHandler
        if (!wasTaskInvoked) {
            postResult(result);
        }
    }

4)   mTask.execute();// Source code analysis

call ladder:
AsyncTask executeOnExecutor->SerialExecutor execute(mWorker//futuretask)-->ArrayDeque.offer(runnable)-->
scheduleNext-->mTasks.poll()&THREAD_POOL_EXECUTOR.execute(futureTask)
Description: futuretask Offer (runnable) is the producer thread. Put futuretask into queue
THREAD_ POOL_ EXECUTOR. Execute (future task) is a consumer thread The thread pool executes runnable run->futureTask. run->callable. call
SerialExecutor is a queueu, and all multithreads become serial. Thread execution thread pool THREAD_POOL_EXECUTOR.
So is asynctask multi-threaded or single threaded? See the appendix for the answers

  public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }
/*Parameter Description: sdefaultexecution = object of task queue thread pool class (SerialExecutor)*/
  public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,Params... params) {
        onPreExecute();//1 main thread initialization
        mWorker.mParams = params;//2 add parameters to the task
        exec.execute(mFuture);//3. Execute a task / / exec = sdefaultexecution = the object of the task queue thread pool class (SerialExecutor)
        return this;
    }
/*exec.execute(mFuture);Description: it belongs to the method of task queue thread pool class (SerialExecutor) */
  private static class SerialExecutor implements Executor {
        // SerialExecutor = static inner class, that is, all instantiated AsyncTask objects are public
        // One bidirectional queue is maintained inside the SerialExecutor; The capacity is adjusted according to the number of elements
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;
        // execute() is decorated with synchronized lock
        // That is to say, the lock enables the queue to ensure that the tasks in AsyncTask are executed serially
        // That is, multiple tasks need to be added to the queue one by one; Then, after executing the queue header, execute the next one, and so on
        public synchronized void execute(final Runnable r) {
            mTasks.offer(new Runnable() {// Passing in the instance object of the instantiated FutureTask class is equivalent to adding a new task to the queue
                public void run() {
                    try {
                        r.run();//Focus: implement futuretask The core of run is actually callable's call time-consuming business logic
                    } finally {
                        scheduleNext();//Take task
                    }
                }
            });
            if (mActive == null) {// If there is no task execution at present, take one execution from the queue
                scheduleNext();
            }
        }
        protected synchronized void scheduleNext() {       
            if ((mActive = mTasks.poll()) != null) {// 1. Take out the queue header task
                THREAD_POOL_EXECUTOR.execute(mActive);// 2. Execute the extracted queue header task, that is, call the THREAD_POOL_EXECUTOR class of execution task
            }
        }
    }

Keywords: Android

Added by dodgyJim on Thu, 10 Feb 2022 12:59:56 +0200