AsyncTask源码解析

来源:互联网 发布:mac 重新安装jenkins 编辑:程序博客网 时间:2024/05/22 11:44

AsyncTask类是Android设计的一个执行异步方法的类,我们可以利用这个类执行一些耗时的任务,然后根据结果更新UI,在执行任务时,也可以更新UI,如设置进度条的进度等等。今天,我们从源码分析这个类,学习执行异步方法的思想,这对我写异步框架应该会起到帮助。Show me the code !!

从属性开始,我分为2部分:(1)线程池的初始化。(2)普通属性。

(1)线程池的初始化
直接看代码:

private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();// We want at least 2 threads and at most 4 threads in the core pool,// preferring to have 1 less than the CPU count to avoid saturating// the CPU with background workprivate static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;private static final int KEEP_ALIVE_SECONDS = 30;// 线程工厂,用来为线程池创建工作线程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());    }};// 任务队列,当线程池的工作线程大于核心线程CORE_POOL_SIZE,新的任务便会加入到这个任务队列中,这里定义队列大小为128private static final BlockingQueue<Runnable> sPoolWorkQueue =        new LinkedBlockingQueue<Runnable>(128);// 真正执行任务的线程池public static final Executor THREAD_POOL_EXECUTOR;// 静态块static {    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(            CORE_POOL_SIZE,       // 核心线程数            MAXIMUM_POOL_SIZE,    // 最大线程数            KEEP_ALIVE_SECONDS,   // 非核心线程闲置的时间            TimeUnit.SECONDS,     // KEEP_ALIVE_SECONDS的单位            sPoolWorkQueue,       // 任务队列            sThreadFactory);      // 线程工厂    // 设置核心线程闲置时,超过KEEP_ALIVE_SECONDS也被销毁,这里是1秒    threadPoolExecutor.allowCoreThreadTimeOut(true);    THREAD_POOL_EXECUTOR = threadPoolExecutor;}

在静态块中,一开始便初始化了一个线程池。更多关于线程池,请参考我上一篇博文Android线程池浅析。

(2)普通属性

// 这个是加入任务的线程池,接下来会分析public static final Executor SERIAL_EXECUTOR = new SerialExecutor();// Handler处理消息的标志private static final int MESSAGE_POST_RESULT = 0x1;private static final int MESSAGE_POST_PROGRESS = 0x2;// 默认执行任务的线程池,定义为SerialExecutor,待会分析private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;private static InternalHandler sHandler;// 异步任务,待会分析private final WorkerRunnable<Params, Result> mWorker;private final FutureTask<Result> mFuture;// 状态private volatile Status mStatus = Status.PENDING;// 原子性布尔变量,用于判断是否取消和执行的标志private final AtomicBoolean mCancelled = new AtomicBoolean();private final AtomicBoolean mTaskInvoked = new AtomicBoolean();

普通属性我们简单的分析了一下,上面提到SerialExecutor线程池,我们来看看代码:

private static class SerialExecutor implements Executor {    final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();    Runnable mActive;    public synchronized void execute(final Runnable r) {        // 将Runnable任务加入到mTasks队列中        mTasks.offer(new Runnable() {            public void run() {                try {                    r.run();                } finally {                    scheduleNext();                }            }        });        // 如果没有任务在执行,就开始执行任务        if (mActive == null) {            scheduleNext();        }    }    protected synchronized void scheduleNext() {        // 从mTasks队列取出任务,并加入到THREAD_POOL_EXECUTOR线程池执行任务        if ((mActive = mTasks.poll()) != null) {            THREAD_POOL_EXECUTOR.execute(mActive);        }    }}

从代码可以看出,SerialExecutor是临时保存任务的,真正执行任务的是THREAD_POOL_EXECUTOR线程池。从代码还看出,AsyncTask是串行执行的,这点很重要。还涉及到队列的小知识,如果mTasks没有元素Runnable的话,调用mTasks.poll()会返回null,不会阻塞。
属性中还定义了状态,有以下3种:

 public enum Status {    /**     * Indicates that the task has not been executed yet.     */    PENDING,    /**     * Indicates that the task is running.     */    RUNNING,    /**     * Indicates that {@link AsyncTask#onPostExecute} has finished.     */    FINISHED,}

好了,属性部分到这里已经看完了,我们看看构造函数吧:

public AsyncTask() {    mWorker = new WorkerRunnable<Params, Result>() {        public Result call() throws Exception {            ...        }    };    mFuture = new FutureTask<Result>(mWorker) {        @Override        protected void done() {            ...        }    };}

构造函数主要初始化mFuture,里面的实现代码再分析。为什么要使用FutureTask呢?那是因为AsyncTask任务需要可取消的功能,而FutureTask正好满足需求。关于FutureTask我也写了一篇博文,请参考FutureTask源码浅析。
我们要执行AsyncTask时,要调用它的execute,代码如下:

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

@MainThread表示要在主线程执行,至于为什么,待会我一一道来。我们继续跟踪executeOnExecutor方法:

@MainThreadpublic final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,        Params... params) {    // 如果当前状态不是Status.PENDING,直接报错。    // 这就表明了,一个AsyncTask只能执行一次。    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,这个方法是钩子方法,子类可以选择重写    onPreExecute();    // 把我们传入的参数交给mWorker    mWorker.mParams = params;    // 开始执行mFuture任务    exec.execute(mFuture);    return this;}

我们先来看看mWorker。它是一个WorkerRunnable,实现Callable接口,如果你知道FutureTask,应该知道为什么要实现Callable。

private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {    // 定义了参数,AsyncTask就是用过这个属性,把参数传进来使用的    Params[] mParams;}

调用exec.execute(mFuture)便开始执行任务,上面已经分析过了,其实是先加入一个队列,然后交给THREAD_POOL_EXECUTOR线程池开启线程执行。
我们看看mFuture执行任务的代码,那么得回到初始化mFuture的代码了,也就是构造函数:

mWorker = new WorkerRunnable<Params, Result>() {    public Result call() throws Exception {        // 设置这个任务已经在执行了        mTaskInvoked.set(true);        // 设置线程优先级,处于THREAD_PRIORITY_BACKGROUND        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);        // noinspection unchecked        // 这里开始执行我们子类重写的doInBackground方法        Result result = doInBackground(mParams);        Binder.flushPendingCommands();        // 调用postResult方法,里面主要是调用        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);        }    }};

如果你对FutureTask熟悉的话,应该知道,FutureTask执行任务会先调用Callable的call方法。上面的代码中,mWorker会先执行call方法,然后mFuture的done方法才会调用。mWorker的call方法中,先调用了我们子类重写的doInBackground方法,然后调用了postResult方法。我们看看postResult方法的代码:

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

从代码可以知道,postResult就是把任务执行的结果通过Handler(消息机制)传到主线程。如果对消息机制不了的,可以看我写的3篇关于消息机制的博文Android消息机制(1)- 简介。getHandler得到的是主线程的Handler,代码如下:

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

我们再来看看自定义的InternalHandler代码:

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

看InternalHandler重写的handleMessage方法,主要处理2个消息事件:MESSAGE_POST_RESULT和MESSAGE_POST_PROGRESS。postResult方法传过来的是MESSAGE_POST_RESULT事件,这里涉及到一个类,AsyncTaskResult,代码:

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

其实就是一个保存数据和AsyncTask的包装类。
我们回到InternalHandler处理MESSAGE_POST_RESULT事件,调用了result.mTask.finish,从AsyncTaskResult看出,其实也就是执行AsyncTask的finish方法,代码如下:

private void finish(Result result) {    if (isCancelled()) {        // 如果任务取消了,调用onCancelled方法        onCancelled(result);    } else {        // 如果任务没有取消,调用onPostExecute方法        onPostExecute(result);    }    // 更新状态    mStatus = Status.FINISHED;}

finish方法代码很简单,不用多说。InternalHandler还可以处理一个事件,MESSAGE_POST_PROGRESS,作用是在执行doInBackground方法时,还能通过调用publishProgress方法更新UI。
我们先看看publishProgress方法:

@WorkerThreadprotected final void publishProgress(Progress... values) {    if (!isCancelled()) {        // 如果任务没有取消,分发消息给InternalHandler处理        getHandler().obtainMessage(MESSAGE_POST_PROGRESS,                new AsyncTaskResult<Progress>(this, values)).sendToTarget();    }}

主要是分发消息给InternalHandler处理,InternalHandler调用result.mTask.onProgressUpdate(result.mData)方法处理事件,也就是交给AsyncTask的onProgressUpdate方法处理。而onProgressUpdate是一个挂钩方法,交给子类去实现。
接下来给出子类可以重写和必须重写的方法,主要是看一下:

// 子类必须重写,执行异步的方法@WorkerThreadprotected abstract Result doInBackground(Params... params);// 其他方法子类可以选择重写,挂钩方法@MainThreadprotected void onPreExecute() {}@SuppressWarnings({"UnusedDeclaration"})@MainThreadprotected void onPostExecute(Result result) {}@SuppressWarnings({"UnusedDeclaration"})@MainThreadprotected void onProgressUpdate(Progress... values) {}@SuppressWarnings({"UnusedParameters"})@MainThreadprotected void onCancelled(Result result) {    onCancelled();}    @MainThreadprotected void onCancelled() {}

到这里,相信你对AsyncTask的机制已经很熟悉了。还有一个,AsyncTask是可取消的,我们看看取消的代码:

public final boolean cancel(boolean mayInterruptIfRunning) {    // 设置取消标志    mCancelled.set(true);    // 调用FutureTask的取消方法    return mFuture.cancel(mayInterruptIfRunning);}// 判断是否取消public final boolean isCancelled() {    return mCancelled.get();}

FutureTask调用cancel方法传入了一个参数,通过解读FutureTask源码可知,如果参数mayInterruptIfRunning为true的话,会立刻中断线程,并设置Interrupt标志。如果为false,则会继续等待线程执行完,设置Cancel标志。
我还在想AsyncTask的cancel方法为什么没有调用onCancelled方法呢,原来我之前对中断线程有误解,正好这里更正了我对线程中断的理解。我原以为调用Thread的interrupt()方法,run方法就不会继续往下执行,直接跳出run方法,这种想法完全是错误的。其实调用Thread的interrupt()方法,如果Thread处于阻塞状态,如处于sleep或者wait,此时,Thread就会收到中断的信号,提前终止阻塞状态,同时抛出InterruptedException异常,然后继续往下执行。如果Thread并没有阻塞,调用Thread的interrupt()方法并不会起效果,run方法还是会继续执行下去。为了证明这点,我特意写了个demo,代码:

public class MainActivity extends Activity {    // 阻塞队列    private LinkedBlockingQueue<Integer> queue;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        queue = new LinkedBlockingQueue<>();        final Thread thread = new Thread(new Runnable() {            @Override            public void run() {                int result;                try {                    // 从队列取出元素                    result = queue.take();                } catch (InterruptedException e) {                    // 处理Interrupted异常                    e.printStackTrace();                    result = -1;                }                Log.e(getClass().getName(), "结果为" + result);                sayHello();            }        });        thread.start();        // 2秒后调用thread.interrupt方法        new Handler().postDelayed(new Runnable() {            @Override            public void run() {                thread.interrupt();            }        }, 2000);    }    private void sayHello() {        Log.e(getClass().getName(), "hello, i executed ----------- ");    }}

打印的结果如下:
打印结果
从打印结果可以知道,sayHello方法还是会执行的,证明我刚才对Thread.interrupt()方法的理解是正确的。

我们再来看调用AsyncTask的cancel(true)方法(因为false不会中断任务线程),我们结合mFuture初始化代码看:

mWorker = new WorkerRunnable<Params, Result>() {    public Result call() throws Exception {        // 设置这个任务已经在执行了        mTaskInvoked.set(true);        // 设置线程优先级,处于THREAD_PRIORITY_BACKGROUND        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);        // noinspection unchecked        // 这里开始执行我们子类重写的doInBackground方法        Result result = doInBackground(mParams);        Binder.flushPendingCommands();        // 调用postResult方法,里面主要是调用        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);        }    }};

因为doInBackground是异步方法,一般在这里阻塞,调用FutureTask的cancel方法后,doInBackground提前结束阻塞,继续往下执行,那么postResult方法也会被执行,接着调用finish方法:

private void finish(Result result) {    if (isCancelled()) {        // 如果任务取消了,调用onCancelled方法        onCancelled(result);    } else {        // 如果任务没有取消,调用onPostExecute方法        onPostExecute(result);    }    // 更新状态    mStatus = Status.FINISHED;}

此时isCancelled为true,所以onCancelled会被执行。这里有学到了关于线程中断的一点小知识,太激动了!!!
到此,整个AsyncTask的原理分析的差不多了,其实我们也能利用这种思想做出我们自己异步框架。我们不是重新做轮子,我们的目标是做更好的轮子。浏览了一下源码,还有个地方你应该知道:

public static void setDefaultExecutor(Executor exec) {    sDefaultExecutor = exec;}

其实我们可以自定义AsyncTask执行任务的线程池和任务排序,默认是顺序执行,如果你想要任务按照你想要的顺序排序,可以自定义Executor,代码回忆一下:

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

如果你并不想要重新定义顺序,只想自定义线程池,执行方法时,调用executeOnExecutor,以下是execute和executeOnExecutor的区别:

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

AsyncTask源码到这里分析已经结束了,发现自己的好好补补线程和队列的知识。

AsyncTask源码下载地址

AsyncTask源码

参考资料

JAVA线程的interrupt

原创粉丝点击