源码分析 —— AsyncTask 完全解析(基于7.0)

在平常开发中执行异步操作很常见的操作,经常在执行异步任务后需要去刷新 UI,这就需要用到 Android 的异步消息处理机制 Handler, 当然我们也可以使用 AsyncTask 去完成,相信大家或多或少都用过 AsyncTask 。

基本用法:

三个泛型 : AsyncTask < Params, Progress, Result >

 1. Params : 启动任务执行传入的参数, 例如HTTP请求的URL , 执行任务需要的数据类型
 2. Progress :  后台执行任务进度的进度类型
 3. Result :  异步任务最终返回的结果类型

几个常用方法:

  • protected void onPreExecute() {}

    • 执行在UI线程, 一般在执行异步任务前做一些UI操作
  • protected Result doInBackground(Params … params) {}

    • 执行在异步线程, 耗时的操作在这个方法中执行。 返回结果被传递到 onPostExecute(), 在执行任务时调用publishProgress() 把执行进度传递给 onProgressUpdate()
  • protected void onProgressUpdate(Progress … progresses) {}

    • 执行在UI线程, 更新进度信息, 调用 publishProgress() 时被回调
  • protected void onPostExecute(Result result) {}

    • 执行在UI线程, 一般在执行完后台任务后更新UI的操作, 显示结果等
  • protected void onCancelled() {}

    • 执行在UI线程, 调用 cancel() 被调用

源码流程

具体用法就不再这里展示了,接下来我们直接看源码,首先看 new AsyncTask() 时候构造方法里面做了什么:

构造方法
public AsyncTask() {
    mWorker = new WorkerRunnable<Params, Result>() {
        public Result call() throws Exception {
           ...省略
        }
    };

    mFuture = new FutureTask<Result>(mWorker) {
        @Override
        protected void done() {
          ...省库
        }
    };
}

2 行: mWorkerWorkerRunnable 类型的内部类对象:

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 方法,具体实现先不看,等调用的时候再具体分析

接着第 8 行: FutureTask ,它实现了 RunnableFuture 接口, RunnableFuture 最终继承 RunnableFuture 接口

public interface RunnableFuture<V> extends Runnable, Future<V> {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     */
    void run();
}

Runnable 接口我们熟悉, 说明 FutureTask 是可以被 Thread 执行的, Future<V> 接口主要是针对Runnable 和 Callable 任务的。提供了三种功能:

  1. 判断任务是否完成 ;
  2. 中断任务 ;
  3. 获取任务执行的结果
mAsyncTask().execute();

接着我们从执行异步任务的起点开始,进入 execute 方法:

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

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

5行:判断任务在运行当中或者已经执行完成, 则报出异常,即每个任务只能执行一次
17行:执行了 onPreExecute() , 当前还在主线程
18行:用 mWorker.mParams 保存传入的参数
19行:调用参数 Executor 类型的 exec 的 execute() 方法, 并把 mFuture 传进去,exec 是在 execute() 方法中传的 sDefaultExecutor。

sDefaultExecutor 是 SerialExecutor 类的实例, SerialExecutor 内部维护了一个 ArrayDeque 类型的队列 mTasks

##mAsyncTask
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new 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);
        }
    }
}

7-12 行:封装传入进来的 mTask 添加到 mTasks 队尾,可以看到在 run() 方法中,执行 mTaskrun() 方法后一定会执行 scheduleNext()
16-17 行:判断 Runnable 类型的 mActive 是否为空,第一次执行肯定为空,则调用 scheduleNext()
21-22 行:取出队首的元素赋给 mActive ,不为空则让线程池去执行这个任务

  • 从上面可以分析出来,当队列中有任务时,任务的执行顺序是当队列中前一个任务执行完成后,后面如果有任务则继续取出并让 THREAD_POOL_EXECUTOR 线程池去执行,执行完成后继续队列中的后一个任务,知道队列中没有元素为止。而重复执行 AsynscTask.execute() 并不会多次触发线程池,只有队列中没有任务时,才会触发线程池执行添加进来的任务。所以,安卓7.0下的 AsyncTask 任务执行是串行的,相当于单线程池的效果。

我们继续看任务的执行,即线程池去执行 mTaskrun() 方法:

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

6 行:callable 就是 FutureTask 构造方法中传入进来的 mWorker,然后赋值给 c
11 行:执行 mWorker 的 call() 方法,并得到执行结果 result , 而 mWorkder 在 AynscTask 构造方法中重写了 call() 方法

##AsyncTask
public AsyncTask() {
    mWorker = new WorkerRunnable<Params, Result>() { 
        public Result call() throws Exception {
            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;
        }
    };

    mFuture = new FutureTask<Result>(mWorker) {...}
}

4 行:标记位 mTaskInvoked 设置为 true
7 行:设置线程优先级 为10。优先级分为 1-10,数值越大优先级越高,默认是5。
9 行:出现了 doInBackground() , 此时方法调用在 mTask 的 run() 中,即在异步线程中执行 doInBackground() 并得到返回结果 result
15 行:postResult(result),字面意思是把结果 post 出去。方法实现先不看,因为后面也调用了此方法再具体分析

继续看 FutureTask run() 方法的 19 行:set(result)

##FutureTask 
protected void set(V v) {
    if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
        outcome = v; 
        U.putOrderedInt(this, STATE, NORMAL);
        finishCompletion();
    }
}

3 行:用 outcome 保存执行结果
5 行的 finishCompletion():

##FutureTask 
private void finishCompletion() {
    // assert state > COMPLETING;
    for (WaitNode q; (q = waiters) != null;) {
        if (U.compareAndSwapObject(this, WAITERS, q,
            for (;;) {
                Thread t = q.thread;
                if (t != null) {
                    q.thread = null;
                    LockSupport.unpark(t);
                }
                WaitNode next = q.next;
                if (next == null)
                    break;
                q.next = null; // unlink to help gc
                q = next;
            }
            break;
        }
    }
    done();
    callable = null;        // to reduce footprint
}

直接看倒数第二行 done() 方法,是不是很眼熟?还记得 AsyncTask 构造方法中 mTask 重写了 done() 方法吗

##AsyncTask
public AsyncTask() {
    mWorker = new WorkerRunnable<Params, 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);
    }
}

在 mTask 重写的 done() 方法中, 把 get() 获取的任务执行结果传递给 postResultIfNotInvoked() 方法,在方法中:如果 mTaskInvoked 不为true,则执行 postResult ; 但是在 mWorker 初始化时就已经 将 mTaskInvoked 为 true,所以一般这个 postResult 执行不到。所以这个 postResult 一般是在 mWorker 执行结束 call() 时执行

private Result postResult(Result result) {
    @SuppressWarnings("unchecked")
    Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,   
            new AsyncTaskResult<Result>(this, result));
    message.sendToTarget();
    return result;
}

可以看到 postResult 中出现了我们熟悉的 Handler 消息机制,传递了一个消息 message, message.what = MESSAGE_POST_RESULT;message.object = new AsyncTaskResult(this,result);

private static class AsyncTaskResult<Data> {
    final AsyncTask mTask;
    final Data[] mData;
    AsyncTaskResult(AsyncTask task, Data... data) {
        mTask = task;
        mData = data;
    }
}

AsyncTaskResult 就是对 AsyncTask 和 result 数据的简单封装。
很容易猜测出来 sHandler 肯定重写了 handleMessage() 方法去接收这个消息并处理:

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

3 行:说明是主线程的 Handler
9 行:msg.what 分两种 MESSAGE_POST_RESULT 和 MESSAGE_POST_PROGRESS,即结果 result 和 进度progress,这里先看 result 的处理

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

如果任务被 cancel() 则调用 onCancelled(),正常执行完调用 onPostExecute(),此时在 Handler 的 handleMessage 中,因此是主线程执行,最后将状态置为 FINISHED

在日常开发中一个常用操作就是在 doInBackgroud 中调用 publishProgress 把执行进度更新给 onProgressUpdate,然后在 onProgressUpdate 根据执行进度来做一些 UI 处理,比如显示进度条之类的:

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

还是通过 sHandler 发送一个 message , what 是 MESSAGE_POST_PROGRESS

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

在 sHandler 的 handleMessage 中,回调了 onProgressUpdate ,明显执行在主线程

到这里,整个 AsyncTask 的执行流程就结束了,看起来好像方法东跳来西跳去有点晕,其实自己对着源码多走几遍就很清晰了
下面有个比较清晰的流程图,借用自 (https://www.jianshu.com/p/e60c3bb03d61)
这里写图片描述

cancel()

此外,在 AsyncTask 中有一个小坑要注意一下,对于 cancel 方法的调用:

 * @param mayInterruptIfRunning <tt>true</tt> if the thread executing this
 *        task should be interrupted; otherwise, in-progress tasks are allowed
 *        to complete.
 */
public final boolean cancel(boolean mayInterruptIfRunning) {
    mCancelled.set(true);   // 标志位 mCancelled 设置为 true
    return mFuture.cancel(mayInterruptIfRunning);
}

从官方注释来看,mayInterruptIfRunning 如果为 true 当前异步任务就会被终止,否则该任务会执行完成。而实际开发中,调用 cancel 并不能中断当前执行的任务。

通过源码可以看到,方法内部只是给 AsyncTask 设置一个 “canceled” 状态,然后向运行中的线程发出 interrupt() 调用。在这种情况下,你的线程是不可中断的,也就不会终止该线程。所以,这就需要你主动去检查 AsyncTask 是否已经取消,之后决定是否终止你的操作。因此需要这样操作

public void onProgressUpdate(Integer... value) {
    ...
    if(isCancelled()) 
        return;
    ...
}

@Override
protected Integer doInBackground(Void... mgs) {
    ...
    if(isCancelled()) 
        return null;
    ...
}
...`

另外在需要结束 AsyncTask 的地方:

if(task != null && !task.isCancelled() && task.getStatus() == AsyncTask.Status.RUNNING) {
    task.cancel(true);  
    task = null;  
}

参考:
AsyncTask各版本源码分析
Android AsyncTask 源码解析

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值