Android takes you to fully parse AsyncTask from the perspective of source code

AsyncTask() resolution (6.0)

    public AsyncTask() {
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                return postResult(doInBackground(mParams));
            }
        };

        mFuture = new FutureTask<Result>(mWorker) {
            @Override
            protected void done() {
                try {
                    postResultIfNotInvoked(get());
                } catch (InterruptedException e) {
                    android.util.Log.w(LOG_TAG, e);
                } catch (ExecutionException e) {
                    throw new RuntimeException("An error occured while executing doInBackground()",e.getCause());
                } catch (CancellationException e) {
                    postResultIfNotInvoked(null);
                }
            }
        };
    }

    private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
        Params[] mParams;
    }

This step initializes a WorkerRunnable object of a Callable subclass and a FutureTask object, and then nothing. The essence of AsyncTask is in execute(). Of course, I will come back to analyze the code here later, and skip it for now.

AsyncTask#execute() parsing

    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }

Inside execute(), executeOnExecutor() is just called, and the first parameter sDefaultExecutor is specified. Spoiler: sDefaultExecutor is the reason for the serial execution of AsyncTask, which will be discussed in detail later. Follow up with executeOnExecutor() first.

    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;
    }

First of all, the judgment of the task status shows that the same AsyncTask cannot call the execute() method multiple times, otherwise the cause of the exception will be reported. It means that the task to be executed can only be in the waiting (PENDING) state. Then change the status of the task to RUNNING, and then call onPreExecute(), which is a method exposed by AsyncTask to subclasses. Generally, some preparatory work is done in this method, such as displaying a progress bar. Then call sDefaultExecutor.execute(mFuture). mFuture has already appeared in AsyncTask(). When mFuture is initialized, the object of WorkerRunnable, a subclass of Callable, is passed in. It's time to go back and take a closer look at the mWorker object.

    mWorker = new WorkerRunnable<Params, Result>() {
        public Result call() throws Exception {
            mTaskInvoked.set(true);
            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            return postResult(doInBackground(mParams));
        }
    };

First set the flag mTaskInvoked to true, and then set the thread priority to the background thread. Then call doInBackground(), doInBackground() is an abstract method that subclasses must implement. Generally, we call time-consuming operations in this method, such as downloading files. Then pass the returned parameter Result as a parameter to postResult. follow up.

    private Result postResult(Result result) {
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }

    private static InternalHandler sHandler;
    private static Handler getHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new InternalHandler();
            }
            return sHandler;
        }
    }

    private static class InternalHandler extends Handler {
        public InternalHandler() {
            super(Looper.getMainLooper());
        }

        @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;
                case MESSAGE_POST_PROGRESS:
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }

Note that the sHandler here is a static member variable, and when a singleton is obtained, the MainLooper is passed. This also means that the switch from the child thread to the main thread, that is, InternalHandler#handleMessage() will be called in the main thread. InternalHandler calls AsyncTask#finish() after receiving the MESSAGE_POST_RESULT message. follow up.

    private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }

It is generally believed that AsyncTash exposes four methods for subclasses to call: onPreExecute(), doInBackground(), onProgressUpdate(), and onPostExecute(). In fact, there is an uncommon method onCancelled(String result) and an overloaded method onCancelled(). Here, it will first determine whether the task has been cancelled. If it has been cancelled, execute onCancelled(), otherwise execute onPostExecute(). This can also reflect a truth. Even if the task.cancel(true) is called to cancel the task, the task is actually still being executed, but the progress and the final notification callback cannot be obtained. Generally, some finishing work is done in the onPostExecute() method, such as: hiding the loading animation. After that, set the status of the task to FINISHED. Analysis here, it seems that the update progress onProgressUpdate() call is not seen. This is because the onProgressUpdate() method is called after manually calling publishProgress(). follow up.

    protected final void publishProgress(Progress... values) {
        if (!isCancelled()) {
            getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();
        }
    }
    ...
    case MESSAGE_POST_PROGRESS:
        result.mTask.onProgressUpdate(result.mData);
        break;

If the task is not cancelled, switch to the main thread to execute onProgressUpdate(). At this point, the five subclass methods of AsyncTask are parsed and completed.

AsyncTask advanced analysis

How is serialization implemented?

At first, this question also confused me for a while. Because each time a new AsyncTask object is created, it should be parallel in reason. Know that I saw the modifier static for SerialExecutor.

sDefaultExecutor strongly references the static instance SERIAL_EXECUTOR of SerialExecutor. Follow up on SerialExecutor.

    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();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }

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

This code is quite interesting. SerialExecutor internally uses a queue to store all tasks. Calling the execute() method will wrap the incoming Runnable object and add it to the mTasks queue. What is the design pattern here? It’s very familiar, I can’t remember it. Now analyze this code step by step.

  1. First call to SerialExecutor#execute()

    First add the Runnable object to the queue, and then judge the current task object mActive (must be null, that is, the scheduleNext() method will be called).

  2. The nth (n>1) call to SerialExecutor#execute()

    1. The current task object mActive is not null, only the Runnable object is added to the queue.
    2. The current task object mActive is null, and the same is true.

In summary, no matter how many times SerialExecutor#execute() is called, scheduleNext() has at most one entry. In scheduleNext(), first take out a task from the task queue mTask, if it is not empty, add the current task object mActive to the thread pool for execution. As mentioned earlier, mActive wraps the real Runnable, and calls scheduleNext() again after calling Runnable#run internally. It is this form of recursion that leads to the serialization of AsyncTask. So is there a way to do it in parallel? Of course there is.

AsyncTask parallel operation

Through the above analysis, it can be found that the parallelism of AsyncTask is mainly because SerialExecutor is at fault. In fact, in executeOnExecutor(), a custom Executor can be passed to implement parallel operations. AsyncTask provides a THREAD_POOL_EXECUTOR serial execution task, in fact, this THREAD_POOL_EXECUTOR supports parallel. That is to say, we only need to call

new MyAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, param);

This enables parallel operation. Of course, a custom Executor can also be passed in. So the question is: since AsyncTask can realize parallel operation, why should it be serialized? In parallel operation, when there are too many tasks, AsyncTask will cause the member function doInBackground of AsyncTask to be called untimely and delay. i.e. doInBackground is not executed immediately after onPreExecute is called. Therefore, it is not recommended to use parallelism in this way.

AsyncTask source code Chinese annotation analysis

public abstract class AsyncTask<Params, Progress, Result> {
    private static final String LOG_TAG = "AsyncTask";
    // 当前的cpu核心数
    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    // 线程池核心容量
    private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
    // 线程池最大容量
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
    // 存活时间
    private static final int KEEP_ALIVE = 1;

    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);

        public Thread newThread(Runnable r) {
            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
        }
    };

    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);

    // 静态并发线程池,可以用来并行执行任务
    public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

    private static final int MESSAGE_POST_RESULT = 0x1;
    private static final int MESSAGE_POST_PROGRESS = 0x2;
    // 默认任务执行者,串行
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    // 持有MainLooper的Handler
    private static InternalHandler sHandler;
    // Callable子类
    private final WorkerRunnable<Params, Result> mWorker;
    // 在mWorker执行完成后,实现具体的逻辑
    private final FutureTask<Result> mFuture;
    // 线程默认等待执行状态
    private volatile Status mStatus = Status.PENDING;
    // 是否被取消
    private final AtomicBoolean mCancelled = new AtomicBoolean();
    // 是否被调用
    private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
    // 串行执行者 ps:AsyncTask的精华就在这里
    private static class SerialExecutor implements Executor {
        // 存放等待执行任务的队列
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        // 当前正在执行的任务
        Runnable mActive;

        public synchronized void execute(final Runnable r) {
            // 将任务插入等待队列,并且在真正调用逻辑代码之后调用scheduleNext()实现串行
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        // 执行任务
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            // 串行的入口
            if (mActive == null) {
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext() {
            // 从任务队列中取出任务
            if ((mActive = mTasks.poll()) != null) {
                // 执行一个任务
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

    public enum Status {
        // 等待执行
        PENDING,
        // 正在执行
        RUNNING,
        // 执行结束
        FINISHED,
    }

    private static Handler getHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new InternalHandler();
            }
            return sHandler;
        }
    }

    /** @hide */
    public static void setDefaultExecutor(Executor exec) {
        sDefaultExecutor = exec;
    }

    public AsyncTask() {
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                // 调用doInBackground()方法
                Result result = doInBackground(mParams);
                Binder.flushPendingCommands();
                // 通过Handler调用onPostExecute()或者onCancelled()
                return postResult(result);
            }
        };

        mFuture = new FutureTask<Result>(mWorker) {
            @Override
            protected void done() {
                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);
                }
            }
        };
    }

    private void postResultIfNotInvoked(Result result) {
        final boolean wasTaskInvoked = mTaskInvoked.get();
        if (!wasTaskInvoked) {
            postResult(result);
        }
    }

    // 通过Handler调用onPostExecute()或者onCancelled()
    private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }

    // 获取任务执行状态。等待(PENDING),正在执行(RUNNING),结束(FINISHED)
    public final Status getStatus() {
        return mStatus;
    }
    // 在子线程中调用。抽象方法,子类必须实现。
    @WorkerThread
    protected abstract Result doInBackground(Params... params);
    // 主线程调用,子类可选择是否实现
    @MainThread
    protected void onPreExecute() {
    }
    // 主线程调用,任务执行完毕后调用,子类可选择是否实现
    @SuppressWarnings({"UnusedDeclaration"})
    @MainThread
    protected void onPostExecute(Result result) {
    }
    // 主线程调用,更新进度,子类可选择是否实现
    @SuppressWarnings({"UnusedDeclaration"})
    @MainThread
    protected void onProgressUpdate(Progress... values) {
    }
    // 取消任务,调用task.cancel(true)后会调用
    @SuppressWarnings({"UnusedParameters"})
    @MainThread
    protected void onCancelled(Result result) {
        onCancelled();
    }    

    @MainThread
    protected void onCancelled() {
    }

    public final boolean isCancelled() {
        return mCancelled.get();
    }


    public final boolean cancel(boolean mayInterruptIfRunning) {
        mCancelled.set(true);
        return mFuture.cancel(mayInterruptIfRunning);
    }

    public final Result get() throws InterruptedException, ExecutionException {
        return mFuture.get();
    }

    public final Result get(long timeout, TimeUnit unit) throws InterruptedException,
            ExecutionException, TimeoutException {
        return mFuture.get(timeout, unit);
    }
    // 执行任务
    @MainThread
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }
    // 真正执行任务的地方(划重点)
    @MainThread
    public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
            Params... params) {
        // 验证任务执行状态,防止execute()被多次调用
        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;
    }

    @MainThread
    public static void execute(Runnable runnable) {
        sDefaultExecutor.execute(runnable);
    }
    // 一般在doInBackground()中调用,内部通过Hanlder调用onProgressUpdate()实现更新UI
    @WorkerThread
    protected final void publishProgress(Progress... values) {
        if (!isCancelled()) {
            getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();
        }
    }
    // 结束任务,在Hanlder中调用
    private void finish(Result result) {
        // 判断任务是否被取消
        if (isCancelled()) {
            // 执行暴露的取消方法
            onCancelled(result);
        } else {
            // 执行暴露的执行完毕方法
            onPostExecute(result);
        }
        // 更改任务状态为结束
        mStatus = Status.FINISHED;
    }

    private static class InternalHandler extends Handler {
        public InternalHandler() {
            // 传递的是主线程的Looper(划重点)
            super(Looper.getMainLooper());
        }

        @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;
                case MESSAGE_POST_PROGRESS:
                    // 更新进度
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }

    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;
        }
    }
}


For more Framework source code analysis, please move to the Framework source code analysis series [Contents]

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325543661&siteId=291194637