We thought

1. The initial AsyncTask

The AsyncTask class is declared as follows:


public abstract class AsyncTask<Params, Progress, Result> {
  .....
}
Copy the code

Params represents the type of the input parameter. Progress represents the Progress of the background task. Result represents the type of the returned Result

2. Use

The AsyncTask class has some code comments at the top that describe how to use an AsyncTask as follows:

* <p>Here is an example of subclassing:</p>
 * <pre class="prettyprint"> * private class DownloadFilesTask extends AsyncTask&lt; URL, Integer, Long&gt; { * protected LongdoInBackground(URL... urls) {
 *         int count = urls.length;
 *         long totalSize = 0;
 *         for (int i = 0; i < count; i++) {
 *             totalSize += Downloader.downloadFile(urls[i]);
 *             publishProgress((int) ((i / (float) count) * 100));
 *             // Escape early if cancel() is called
 *             if (isCancelled()) break; * *}return totalSize;
 *     }
 *
 *     protected void onProgressUpdate(Integer... progress) {
 *         setProgressPercent(progress[0]);
 *     }
 *
 *     protected void onPostExecute(Long result) {
 *         showDialog("Downloaded " + result + " bytes");
 *     }
 * }
 * </pre>

//user
<p>Once created, a task is executed very simply:</p>
 * <pre class="prettyprint">
 * new DownloadFilesTask().execute(url1, url2, url3);
 * </pre>
Copy the code

3. Internal important methods

  • onPreExecute()
@MainThread
  protected void onPreExecute() {}Copy the code

Running in the main thread, asynchronous tasks are called before, usually to do some preparatory work;

  • doInBackground()
@WorkerThread
 protected abstract Result doInBackground(Params... params);
Copy the code

Running in a thread pool, this method is typically used to perform asynchronous tasks, updating progress through the publishProgress method;

  • onProgressUpdate()
@MainThread
    protected void onProgressUpdate(Progress... values) {
    }
Copy the code

The onProgressUpdate() method is called when called with the publishProgress method;

  • onPostExecute()
@MainThread
    protected void onPostExecute(Result result) {
    }
Copy the code

Run in the main thread, will return the results show.

4. Source code analysis

Start with its execute method:

@MainThread public final AsyncTask<Params, Progress, Result> execute(Params... Params) {//sDefaultExecutor is defined as follows, thread poolreturn executeOnExecutor(sDefaultExecutor, params);
    }

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
Copy the code
@MainThread
    public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... Params) {// First check whether it is PENDINGif(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 () onPreExecute(); Mworker. mParams = params; mworker. mParams = params; Exec. Execute (mFuture);return this;
    }
Copy the code

In order to understand the overall process, it is important to understand the above mWorker mFuture.

  • mWorker
private final WorkerRunnable<Params, Result> mWorker; Private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> { Params[] mParams; } @SuppressWarnings({"RawUseOfParameterizedType"}) private static class AsyncTaskResult<Data> { final AsyncTask mTask; final Data[] mData; AsyncTaskResult(AsyncTask task, Data... data) { mTask = task; mData = data; }}}Copy the code
// In the AsyncTask constructor, The mWorker respectively, MFuture initialized public AsyncTask (@ Nullable stars callbackLooper) {mHandler = callbackLooper = = null | | callbackLooper == Looper.getMainLooper() ? getMainHandler() : new Handler(callbackLooper); MWorker = new WorkerRunnable<Params, Result>() {public Result call() throws Exception {// Sets the call totrue
                mTaskInvoked.set(true); // Result result = null; Try {/ / set the thread priority Process. The setThreadPriority (Process. THREAD_PRIORITY_BACKGROUND); // NoInspection unchecked // will be 2.doThe result of InBackground is stored in result result =doInBackground(mParams);
                    Binder.flushPendingCommands();
                } catch (Throwable tr) {
                    mCancelled.set(true); throw tr; } finally {postResult postResult(result); } // return the resultreturnresult; }}; 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

PostResult (result) method

 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

Send a MESSAGE_POST_RESULT message and store the result to mData in AsyncTaskResult, where AsyncTaskResult

@SuppressWarnings({"RawUseOfParameterizedType"}) private static class AsyncTaskResult<Data> { final AsyncTask mTask; final Data[] mData; AsyncTaskResult(AsyncTask task, Data... data) { mTask = task; mData = data; }}Copy the code

GetHandler gets a Handler. Let’s look at how handleMessage’s MESSAGE_POST_RESULT handles this message:

 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) {caseMESSAGE_POST_RESULT: // There is only one result result.mtask. finish(result.mdata [0]);break;
                case MESSAGE_POST_PROGRESS:
                    result.mTask.onProgressUpdate(result.mData);
                    break; }}}Copy the code

Result is AsyncTaskResult, which we saw earlier, mTask where we passed this which is the current AsyncTask, call finish, pass in the result that mData returns, remember what we saw earlier, The returned result is stored in asynctAskResult.mdata.

Let’s look at the Finish method:

Private void finish(Result Result) {// Check whether the onPostExecute function is cancelledif (isCancelled()) {
            onCancelled(result);
        } else{//4. Execute onPostExecute(result); } // Mark the Status as Finish mStatus = status.finished; }Copy the code

Ok, that’s what mWorker does. Next is the mFuture we started with

  • mFuture
private final FutureTask<Result> mFuture; // Initialization is also performed in the AsyncTask constructor, under mWorker, And pass mWorder to 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

postResultIfNotInvoked(get()); As follows:

private void postResultIfNotInvoked(Result result) { final boolean wasTaskInvoked = mTaskInvoked.get(); / / wasTaskInvoked fortrue, previously set to in mWorkertrue
//mWorker = new WorkerRunnable<Params, Result>() {
//            public Result call() throws Exception {
 //               mTaskInvoked.set(true);

        if (!wasTaskInvoked) {
            postResult(result);
        }
    }
Copy the code

FutureTask :

Public FutureTask(Callable<V> Callable) {if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }

public void run() {
        if(state ! = NEW || ! U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))return; //callable <V> c = callable;if(c ! = null && state == NEW) { V result; boolean ran; Mworker. call result = c.call(); // Mworker. call result = c.call(); 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

Ok, this is mFuture, just one more:

exec.execute(mFuture);

Exec sDefaultExecutor SerialExecutor

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

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

SerialExecutor is as follows:

 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(); } finally { scheduleNext(); }}}); // The first time must be null, execute scheduleNextif (mActive == null) {
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext() {// Assign to mActivie, and mtasks. poll takes the first oneif((mActive = mTasks.poll()) ! = null) { THREAD_POOL_EXECUTOR.execute(mActive); }}}Copy the code

Above we pass in the mFuture, which is really just r. mTask is an ArrayDeque

let’s just say it’s the queue. Look at the offer method:

/ / Inserts the specified element at the end of this deque. ** <p>This method is equivalent to {@link#offerLast}.
     *
     * @param e the element to add
     * @return {@code true} (as specified by {@link Queue#offer})
     * @throws NullPointerException if the specified element is null
     */
    public boolean offer(E e) {
        return offerLast(e);
    }
Copy the code

Each time a task is executed, the queue starts at the end of the current deque. ScheduleNext will not execute scheduleNext if mActive is not null when the second thread comes. In fact, after Android 3.0 asyncTasks are executed in serial mode.

The differences are as follows: Before Android 1.6 —— Serial Between Android 1.6 and 3.0 —– Parallel After Android 3.0 —– Serial

However, we can still execute tasks in parallel by calling executeOnExecutor.

Ok, going back to the execute method, we say that r.run is called, but we actually call the mfuture. run method: as we showed above in the mfuture. run method:

Mworker. call result = c.call(); // Mworker. call result = c.call(); ran =true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
Copy the code

Finally, the mworker. call method is called. In the mworker. call method, we complete a series of tasks and call doInBackground onPostExecute to complete the whole call process.

Some of you may have noticed that there’s one more onProgressUpdate method that hasn’t been called yet, We know that onProgressUpdate can only be called if the publishProgress method is called.

@WorkerThread protected final void publishProgress(Progress... Values) {// If not cancelledif(! IsCancelled ()) {getHandler().obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult<Progress>(this, values)).sendToTarget(); }}Copy the code
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) {case MESSAGE_POST_RESULT:
                    // There is only one result
                    result.mTask.finish(result.mData[0]);
                    break;
                caseMESSAGE_POST_PROGRESS:// Yes he is he is he. Call the onProgressUpdate method result. MTask. OnProgressUpdate (result. MData);break; }}}Copy the code

The AsyncTask onProgressUpdate method is now called. The end.