跳至主要內容

AsyncTask 源码解析

JI,XIAOYONG...大约 4 分钟

这是 AsyncTask 源码的简单分析,主要基于《Android 开发艺术探索》一书的内容。

AsyncTask 是 Android 中多线程处理方式之一(其余为 1.HandlerThread、2.IntentService 以及普通的线程 Thread)。

AsyncTask 本质是线程池和 Handler 的包装类,适合实时更新后台任务进度的工作,特别耗时的工作应当交给线程池处理。

AsyncTask 常用方法:

  • onPreExecute()
  • doInBackground()
  • onProgressUpdate()
  • onPostExecute()

AsyncTask 有一下限制:

  1. AsyncTask 对象必须在主线程(UI 线程,下同)创建
  2. AsyncTask 的 execute() 必须在主线程调用,且只能被调用一次
  3. 不能直接调用其 4 种常用方法(见上)

使用

  • 继承自 AsyncTask,重写对应方法。(注意如果需要更新进度,要在 doInBackground() 方法中调用 publishProgress() 方法)
  • UI 线程实例化 AsyncTask 对象,并调用其 execute() 方法,传入参数开始执行。。

概述

在 execute(params) 执行后,将参数 params 传入 mWorker.call() 方法

通过 exec.execute(mFuture) 将其压入 SerialExecutor 线程池中排队,并在 THREAD_POOL_EXECUTOR.execute(mActive) 真正执行。

代码分析

创建对象(代码有节略,下同)

// Creates a new asynchronous task. This constructor must be invoked on the UI thread.
//注意这里的要求,必须在 ui 线程
public AsyncTask(@Nullable Looper callbackLooper) {
    mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
        ? getMainHandler()//此处创建 InternalHandler 用于在 UI 线程处理消息
        : new Handler(callbackLooper);

    mWorker = new WorkerRunnable<Params, Result>() {
        public Result call() throws Exception {
            try {
                result = doInBackground(mParams);//注意这里会调用 doInBackground() 方法,后台线程
            } catch (Throwable tr) {
                mCancelled.set(true);
                throw tr;
            } finally {
                postResult(result);//此处发送 msg 到 mHandler 那里接受处理
            }
            return result;
        }
    };

    mFuture = new FutureTask<Result>(mWorker) {//这里将 mWorker 传了进去
        @Override
        protected void done() {
        }
    };
}

再看 FutureTask

public FutureTask(Callable<V> callable) {
    if (callable == null)
        throw new NullPointerException();
    this.callable = callable; //将 mWorker 当做了他的 callable
    this.state = NEW;       // ensure visibility of callable
}

public void run() {
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                 result = c.call(); //会在这里回调 mWorker 的 call() 方法,即前文所说的 doInBackgroud() 之类的方法
            }
        } finally {
        }
    }

在主线程调用 execute() 方法

@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) {
    if (mStatus != Status.PENDING) { //此处限制 execute() 只能被执行一次
        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; //将参数传入 mWorker,并一并传入 mFuture 中
    exec.execute(mFuture);//将准备好参数、执行时间的 mFuture 排队放入串行线程池中,等待执行

    return this;
}

这里调用了常用方法之一 onPreExecute();

mWorker 和 mFuture 的关系前文已经描述了,在看一下 exec.execute(mFuture) 执行了什么:

exec 是 execute() 传入的,对应于 sDefaultExecutor,再查下去

    /**
     * An {@link Executor} that executes tasks one at a time in serial
     * order.  This serialization is global to a particular process.
     */
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

再看看 SerialExecutor 这个线程池

//SerialExecutor 主要的作用是将这些线程放到线程池中,并按照串行的顺序依次调用
private static class SerialExecutor implements Executor {
    final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
    Runnable mActive;

    public synchronized void execute(final Runnable r) {
        //offer() Inserts the specified element at the end of this deque.
        //将 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);//在这里面才是真正的执行线程的内容
        }
    }
}

再仔细看一下 THREAD_POOL_EXECUTOR

ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
        CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
        sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;

 //Executes the given task sometime in the future.  The task
 //may execute in a new thread or in an existing pooled thread.
ThreadPoolExector.executr()

以上介绍了线程和线程池部分的内容,接下来看一下在主线程和后台线程之间是如何依靠 handler 机制来传递消息的。

关于构造函数,由于我们开发者只能接触到 AsyncTask() 这个构造函数,所以mHandler=getMainHandler()

public AsyncTask() {
    this((Looper) null);
}
//@hide,普通开发者不可见
public AsyncTask(@Nullable Looper callbackLooper) {
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);
            ......
}
    private static Handler getMainHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new InternalHandler(Looper.getMainLooper());
            }
            return sHandler;//sHandler 是一个类变量,取的是主线程的 looper,所以限制了 AsyncTask 只能在主线程实例化
        }
    }

再看一下 InternalHandler 类

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

    @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
    @Override
    public void handleMessage(Message msg) { //在这里处理后台线程发过来的消息,UI 线程
        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;
        }
    }
}

例如,在 doInBackground() 方法中可以使用 publishProgress() 在后台更新进度,即是使用了 handler 发送消息。

@WorkerThread
protected final void publishProgress(Progress... values) {
    if (!isCancelled()) {
        getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                new AsyncTaskResult<Progress>(this, values)).sendToTarget();
    }
}

最后,AsyncTask 的 finish()

private void finish(Result result) {
    //可见,最后会根据情况调用 onCancelled() 或者 onPostExecute()
    if (isCancelled()) {
        onCancelled(result);
    } else {
        onPostExecute(result);
    }
    mStatus = Status.FINISHED;
}
文章标题:《AsyncTask 源码解析》
本文作者: JI,XIAOYONG
发布时间: 2018/04/19 22:04:28 UTC+8
更新时间: 2023/12/30 16:17:02 UTC+8
written by human, not by AI
本文地址: https://jixiaoyong.github.io/blog/posts/7ee9086b.html
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 许可协议。转载请注明出处!
你认为这篇文章怎么样?
  • 0
  • 0
  • 0
  • 0
  • 0
  • 0
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v2.15.8