一、AsyncTask 简介

AsyncTask
public abstract class AsyncTask
extends Object
java.lang.Object
    ↳ android.os.AsyncTask< Params, Progress, Result >

      AsyncTask是一个抽象类,它是由Android封装的一个轻量级异步类,它可以很方便的使用UI线程,执行后台任务,并可以把执行的程序和运行的结果给Ui线程处理,而无需实现Thread和handler。

二、AsyncTask 使用

1、AsyncTask的泛型类型

      异步任务使用的三种类型如下:

Params : 执行时发送给任务的参数类型。
Progress : 后台执行任务进度的进度类型。
Result : 异步任务最终返回的结果类型。

      并非所有类型都始终由异步任务使用。如果不指定,只需使用以下类型Void:

private class MyTask extends AsyncTask<Void, Void, Void> { ... }

2、五个方法

执行异步任务时,任务将执行4个方法:
1、onPreExecute(),刚开始执行的时候调用,可以用于进行一些界面上的初始化操作,比如说显示一个进度条对话框
2、doInBackground(Params...),在onPreExecute()完成执行后立即在后台线程上调用,执行在异步线程, 耗时的操作在这个方法中执行。返回结果被传递到 onPostExecute(), 在执行任务时调用publishProgress()把执行进度传递给 onProgressUpdate()
3、onProgressUpdate(Progress...)执行在UI线程, 更新进度信息, 调用publishProgress() 时被回调。
4、onPostExecute(Result),执行在UI线程, 一般在执行完后台任务后更新UI的操作, 显示结果等
除了上面四个方法,AsyncTask还提供了onCancelled()方法,它同样在主线程中执行,当异步任务取消时,onCancelled()会被调用,这个时候onPostExecute()则不会被调用,但是要注意的是,AsyncTask中的cancel()方法并不是真正去取消任务,只是设置这个任务为取消状态,我们需要在doInBackground()判断终止任务。就好比想要终止一个线程,调用interrupt()方法,只是进行标记为中断,需要在线程内部进行标记判断然后中断线程。

3、AsyncTask 使用的实例

      我在前面的博客里写了一个AsyncTask 使用OKHttp 实现断点下载大文件实例,效果图如下:

      想了解怎么使用的可以看Android 启动服务配合AsyncTask 使用OKHttp 实现断点下载大文件实例这篇文章。

三、 AsyncTask 源码分析

      我打开的是Android 8.1 版本的AsyncTask 源码;

1、构造函数:

/** * Creates a new asynchronous task. This constructor must be invoked on the UI thread. *  创建一个新的异步任务。, 必须在UI线程上调用此构造函数。 */public AsyncTask() {    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() {        public Result call() throws Exception {            ...            return result;        }    };    mFuture = new FutureTask(mWorker) {        @Override        protected void done() {            ...        }    };}

      在构造函数里面,能看到创建了三个变量,分别是mHandlermWorker以及mFuture

(1)mHanlder

      因为第二个以及第三个构造函数都被隐藏的缘故,所以 mHandler 只能是 getMainHandler(),我们看下这个方法的实现。

private static Handler getMainHandler() {    synchronized (AsyncTask.class) {        if (sHandler == null) {            sHandler = new InternalHandler(Looper.getMainLooper());        }        return sHandler;    }}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;            // 发布进度消息            case MESSAGE_POST_PROGRESS:                result.mTask.onProgressUpdate(result.mData);                break;        }    }}

      AsyncTask 里面使用的是InternalHanler ,里面绑定了主线程的Looper和消息队列。如果handler收到的是MESSAGE_POST_RESULT消息,就会执行finish()方法,最后调用onPostExecute()方法。如果handler收到的是MESSAGE_POST_PROGRESS消息,就会执行onProfressUpdate()方法。

(2)mWorker

      mWorker 是 WorkerRunnable 类型的内部类对象:

private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {    Params[] mParams;}public interface Callable<V> {    /**     * Computes a result, or throws an exception if unable to do so.     *     * @return computed result     * @throws Exception if unable to compute a result     */    V call() throws Exception;}

       WorkerRunnable 实现了Callable 接口,接口中只有一个 call() 方法。因为不论是继承Thread类还是实现Runnable 方法,执行完任务以后都无法直接返回结果。而Callable接口弥补了这个缺陷,当call()方法执行完毕以后会返回一个泛型对象,而mWorker 重写了 call方法。
      Callable 接口实际上是属于Executor 框架中的功能类,Callable 接口与Runnable 接口的功能类似,但提供了比Runnable更强大的功能,主要表现为以下三点:
(1)Callable可以在任务接受后提供一个返回值,Runnable无法提供这个功能。
(2)Callable中call()方法可以抛出异常,而Runnablerun()方法不能抛出异常。
(3)运行Callable可以拿到一个Future对象,Future对象表示异步计算的结果,他提供了检查计算是否完成的方法。由于线程属于异步计算模型,因此无法从别的线程中得到函数的返回值,在这种情况下就可以使用Future来监视目标线程调用call()方法的情况,但调用Futureget()方法以获取结果时,当前线程就会阻塞,直到call()方法的返回结果。
       我们继续看下call()方法里面执行了什么:

public Result call() throws Exception {    //先设置mTaskInvoked为true,表示线程已经开始    mTaskInvoked.set(true);    Result result = null;    try {        //设置当前的线程级别为标准优先级后台线程级别        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);        //noinspection unchecked        result = doInBackground(mParams);        Binder.flushPendingCommands();    } catch (Throwable tr) {        mCancelled.set(true);        throw tr;    } finally {        postResult(result);    }    return result;}private Result postResult(Result result) {    @SuppressWarnings("unchecked")    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,            new AsyncTaskResult(this, result));    message.sendToTarget();    return result;}

       首先要明确的一点,call() 一定是在线程池的子线程中执行的,并没有执行在主线程中。当call() 执行的时候,先设置mTaskInvokedtrue,表示线程已经开始。接下来设置当前的线程级别为标准优先级后台线程级别,使您的线程略低于正常优先级,因此它将不太可能影响用户界面的响应性。然后在子线程中执行doInBackground()方法并将处理结果返回,最后将执行完的结果交给postResult()。继续看postResult() 方法,getHandler 获取的其实就是刚刚定义的mHandler,这时mHandler就会收到的是MESSAGE_POST_RESULT消息,就会执行finish()方法,最后调用onPostExecute()方法。

(3)mFuture

public class FutureTask<V> implements RunnableFuture<V> {    ... }public interface RunnableFuture<V> extends Runnable, Future<V> {    /**     * Sets this Future to the result of its computation     * unless it has been cancelled.     * 将此Future设置为其计算结果,除非它已被取消。     */    void run();}

      mFuture 实现了RunnableFuture接口,而Runnablefuture 最终继承Runnable 和 Future 接口,这里我们说一下Future接口:
  在Future接口中声明了5个方法,下面依次解释每个方法的作用:
1、cancel方法用来取消任务,如果取消任务成功则返回true,如果取消任务失败则返回false。参数mayInterruptIfRunning表示是否允许取消正在执行却没有执行完毕的任务,如果设置true,则表示可以取消正在执行过程中的任务。如果任务已经完成,则无论mayInterruptIfRunningtrue还是false,此方法肯定返回false,即如果取消已经完成的任务会返回false;如果任务正在执行,若mayInterruptIfRunning设置为true,则返回true,若mayInterruptIfRunning设置为false,则返回false;如果任务还没有执行,则无论mayInterruptIfRunningtrue还是false,肯定返回true
2、isCancelled方法表示任务是否被取消成功,如果在任务正常完成前被取消成功,则返回 true。
3、isDone方法表示任务是否已经完成,若任务完成,则返回true;
4、get()方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回;
5、get(long timeout, TimeUnit unit)用来获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null。
也就是说Future提供了三种功能:
(1)判断任务是否完成;
(2)能够中断任务;
(3)能够获取任务执行结果。
  因为Future只是一个接口,所以是无法直接用来创建对象使用的,因此就有了下面的FutureTask。所以FutureTask既能当做一个Runnable直接被Thread执行,也能作为Future用来得到Callable的计算结果。
  我们来看下mFuturedone 方法实现了哪些内容:

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

  当任务的状态的变化时就会执行done 此方法,然后可以看到执行了postResultIfNotInvoked()方法。当wasTaskInvokedfalse的时候执行postResult(result) 方法,但是在执行mWorkercall()方法的时候,已经将wasTaskInvoked设为了true。所以当任务执行完后或者取消后才会执行postResult(result)这个方法。

2、execute 方法

  在实例化了AsyncTask对象之后,我们就可以调用AsyncTask的execute方法执行任务,execute代码如下所示:

@MainThreadpublic final AsyncTask execute(Params... params) {    return executeOnExecutor(sDefaultExecutor, params);}@MainThreadpublic final AsyncTask executeOnExecutor(Executor exec,        Params... params) {    if (mStatus != Status.PENDING) {        switch (mStatus) {            case RUNNING:                //如果当前AsyncTask已经处于运行状态,那么就抛出异常,不再执行新的任务                throw new IllegalStateException("Cannot execute task:"                    + " the task is already running.");            case FINISHED:                //如果当前AsyncTask已经把之前的任务运行完成,那么也抛出异常,不再执行新的任务                throw new IllegalStateException("Cannot execute task:"                    + " the task has already been executed "                    + "(a task can be executed only once)");        }    }    //将AsyncTask的状态置为运行状态    mStatus = Status.RUNNING;    //在真正执行任务前,先调用onPreExecute方法    onPreExecute();    // sDefaultExecutor 执行 mFuture    mWorker.mParams = params;    exec.execute(mFuture);    //最后将AsyncTask自身返回    return this;}

  在execute方法上,注意到有@MainThread,所以这个方法是在主线程中执行的。在方法里执行了executeOnExecutor()方法,并把sDefaultExecutor也传了进去,我们先看executeOnExecutor() 方法。一开始先判断了AsyncTask的状态,当状态不是PENDING即任务尚未开始执行时,抛出两个异常并不再执行,这就意味着Asynctask只能执行一次。当AsyncTask 的状态为尚未开始执行的时候,将状态改为运行状态并执行onPreExecute()方法,用 mWorker.mParams 保存传入的参数,然后调用sDefaultExecutor执行 mFuture
  sDefaultExecutorSerialExecutor的一个实例:

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();private static class SerialExecutor implements Executor {    // mTasks是一个维护Runnable的双端队列实例,ArrayDeque没有容量限制,其容量可自增长    final ArrayDeque mTasks = new ArrayDeque();    // mActive 正在执行的任务    Runnable mActive;    public synchronized void execute(final Runnable r) {        // 向队尾插入一个Runnable        mTasks.offer(new Runnable() {            public void run() {                try {                    // 开始执行任务                    r.run();                } finally {                    // 调用scheduleNext() 执行下一个Runnable                    scheduleNext();                }            }        });        // 如果mActive 为空 执行下一个Runnable        if (mActive == null) {            scheduleNext();        }    }    protected synchronized void scheduleNext() {        // mTasks.poll() 取出队列头部的元素,并从队列中移除         // 将取出队列的Runnable 赋值给mActive,如果不为空则交给THREAD_POOL_EXECUTOR去执行        if ((mActive = mTasks.poll()) != null) {            THREAD_POOL_EXECUTOR.execute(mActive);        }    }}

  SerialExecutor是一个串行的线程池,当sDefaultExecutor执行execute()方法的时候,开始执行SerialExecutor类的execute() 方法,会向mTasks 的队尾添加一个新建的Runnable,其内部会调用 r.run();无论任务r正常执行完成还是抛出异常,都会在finally中执行scheduleNext方法,用于执行mTasks中的下一个任务。因此,我们可以看出SerialExecutor是一个接一个的处理任务,是串型执行任务,而不是并行执行任务。当mActive 为空的时候, 也会开始执行下一个Runnable。这里的任务都是交给THREAD_POOL_EXECUTOR(线程池)去处理的,我们看下THREAD_POOL_EXECUTOR

/** * An {@link Executor} that can be used to execute tasks in parallel. */public 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;}

  THREAD_POOL_EXECUTOR指的就是threadPoolExecutor,他的核心线程和线程池允许创建的最大线程数都是由CPU的核数来计算出来的,它采用的阻塞队列是LinkedBlockingQueue

总结

  关于源码的讲解到这里就结束了,我们来梳理下整个流程。当我们继承AsyncTask实现自定义的异步任务时,会初始化三个值,分别是mHandlermWorker以及mFuture。然后当我们调用AsyncTaskexecute方法执行任务的时候,在execute()方法里先判断一下状态,然后将状态改为运行状态并执行onPreExecute()方法,用 mWorker.mParams 保存传入的参数,然后通过SerialExecutor线程池用于任务的排队,让需要执行的多个耗时任务,按顺序排列,最后再调用THREAD_POOL_EXECUTOR线程池去真正地执行任务mFuture,进而会执行mWorkercall() 方法,先设置mTaskInvokedtrue,表示线程已经开始。接下来设置当前的线程级别为标准优先级后台线程级别,然后在子线程中执行doInBackground()方法并将处理结果返回,最后将执行完的结果交给postResult()。在postResult方法中,获取到mHandler,这时mHandler就会收到的是刚刚发出的MESSAGE_POST_RESULT消息,然后执行finish()方法,最后调用onPostExecute()方法,并将AsyncTask的状态设置为完成状态。

更多相关文章

  1. 让editView、AutoCompleteTextView开始捕获的焦点
  2. Android(安卓)Gradle Study
  3. android studio中运行main方法报错问题解决方法
  4. Android(安卓)Studio 解决方法No JVM installation found. Pleas
  5. Android(安卓)AM命令行启动程序的方法
  6. ReactNative调用原生封装的代码和控件
  7. Android点击监听事件
  8. 浅谈Java中Collections.sort对List排序的两种方法
  9. Python list sort方法的具体使用

随机推荐

  1. 一步步教你用Android(安卓)Google Map
  2. GDB + gdbserver 远程调试android native
  3. 在Ubuntu上下载、编译和安装Android最新
  4. android中Content Provider
  5. Android(安卓)LinearLayout的布局属性介
  6. android
  7. android 获取路径目录方法以及判断目录是
  8. android 数字键盘使用
  9. android中从图库中选取图片
  10. 原始Android的目标机代码结构