Android基于源码分析AsyncTask的工作流程

原创 2015年11月18日 15:14:06


AsyncTask简介

    AsyncTask是一种轻量级的异步任务类,它实质上也是对handler和thread做了封装,使用线程池执行后台任务,是一个比较好用的异步类。

AsyncTask的3个参数和4个步骤

  3个参数:

        params:我们传递给异步任务执行的参数类型;

        progress:异步任务在执行的时候,会将执行的进度返回给UI的参数类型;

        Result:异步任务执行结束后返回的数据参数类型。

  4个步骤:

        onPreExecute():这个方法是在执行异步任务之前执行的,通常用来做一些控件的初始化工作,此方法在UI线程中执行。

        doInBackground(Params…) :在onPreExecute()方法后执行,这个方法就是在工作线程中执行的,可以做一些相对耗时的任务,在执行的时候,如果调用        publishProgress(Progress... values)方法,可以更新任务的进度,执行结束后,将执行的结果返回给onPostExecute(Result result)处理。

        onProgressUpdate(Progress... values):该方法在UI线程中执行,如在异步任务执行时(doInBackground()里面)调用publishProgress()方法,这个方法可以得到返回的进度参数,然后在控件上更新进度条。

        onPostExecute(Result result):当异步操作任务执行完成后会将结果返回到这个方法,我们可以将返回的结果显示在控件上,这个方法这是在UI线程上执行的。

AsyncTask的源码分析

    上面说了那么多,都是一些很理论的东西,只知道有这么回事儿,但是究竟为什么要这么执行呢?不急,我们从源码的角度来看看吧!

    我们知道,要使用AsyncTask,必须先自己定义一个类继承它(假如是MyAsyncTask),然后在主线程中创建这个类,使用MyAsyncTask().execute(params...)来执行,好了基础的代码这里就不贴,重点在源码分析嘛!(注意我这里是基于Android4.4的源码),当我们点到execute这个方法,跳到系统源码类中的:

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

这个方法没什么,只有一个参数sDefaultExecutor,这个参数是啥:

    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 final InternalHandler sHandler = new InternalHandler();

    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    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();

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

sDefaultExecutor实际上就是一个扩展了Executor的SerialExecutor内部类,这里sDefaultExecutor实际上就是一个串行的线程池,也就是说AsyncTask所有的任务在这个线程池中排队执行。这个方法里面,我们主要先看形参Runnable,在try{}语句中有个r.run(),凭直觉,这里应该就是开启线程干活了。这儿先留个伏笔,我们接着往下看:

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

这里我们看到了onPreExecute(),从这也说明了它是在执行异步操作之前先执行的,我们可以看到:onPreExecute()、doInBackground(Params... params)、onProgressUpdate(Progress... values)、onPostExecute(Result result)这几个方法都是protected修饰的,同时public abstract class AsyncTask<Params, Progress, Result>是一个抽象类,所以我们一般是自己写一个类继承AsyncTask,然后子类里面实现这些方法来使用。接着看,这里有2个很重要的成员变量参数,mWorker和mFuture,在看到exec.execute(mFuture)这一行代码的时候,对应前面说的伏笔,那么mFuture这个就是我们要的Runnable对象,r.run(),也就是mFuture干活了。那么这2个这么重要成员变量哪来的呢?接着看:

    /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     */
    public AsyncTask() {
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                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);
                }
            }
        };
    }

这个AsyncTask()实际上是构造函数,在我们创建自己的AsyncTask(MyAsyncTask)的时候,这个类就在UI线程中被调用了。先看看mWorker,这里直接创建了WorkerRunnable<Params, Result>()这个静态抽象的内部类对象,我们看看这是个啥:

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

看到最后,发现mWorker是实现了Callable接口的类,这个call()方法,在上面创建的时候实现。再看看mFuture是啥,这里要点到FutureTask类看:

    /**
     * Creates a {@code FutureTask} that will, upon running, execute the
     * given {@code Callable}.
     *
     * @param  callable the callable task
     * @throws NullPointerException if the callable is null
     */
    public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }

前面mFuture = new FutureTask<Result>(mWorker)这行代码中,就直接把mWorker传到了FutureTask的成员变量this.callable = callable中的this.callable中。好,看看FutureTask是什么东东:

public class FutureTask<V> implements RunnableFuture<V>
/**
 * A {@link Future} that is {@link Runnable}. Successful execution of
 * the {@code run} method causes completion of the {@code Future}
 * and allows access to its results.
 * @see FutureTask
 * @see Executor
 * @since 1.6
 * @author Doug Lea
 * @param <V> The result type returned by this Future's {@code get} method
 */
public interface RunnableFuture<V> extends Runnable, Future<V> {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     */
    void run();
}

终于看清楚啦,这个mFuture就是咱们需要的Runnable!干活的确定是mFuture了。好我们回过头看看executeOnExecutor方法中的:
exec.execute(mFuture);

这个exec就是传进来的sDefaultExecutor,而sDefaultExecutor我们上面看了,实际就是SerialExecutor类,看看类里面的:

 public synchronized void execute(final Runnable r) {
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }

第5行r.run();到这里,也就是说执行mFuture.run()了,我们再次看看FutureTask中的run():

    public void run() {
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         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);
        }
    }

挑重点看,这个方法里把之前创建FutureTask的时候mFuture = new FutureTask<Result>(mWorker)中的mWorker付给Callable<V> c,然后执行result = c.call(),也就是说

mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                return postResult(doInBackground(mParams));
            }
        };

这个call()方法执行了。仔细看看这个方法里面,return postResult(doInBackground(mParams));终于看到了doInBackgroud了,原来,doInBackground永远执行在Runnable中,也就是说在工作线程中执行,所以我们可以再这里面做一些稍微耗时的工作。当doInBackground返回结果了,我们接着看postResult(doInBackground(mParams)):

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

是不是一种似曾相识的感觉油然而生,这里居然就是使用的handler发送的消息啊!我们看看这个内部类sHandler:

private static final InternalHandler sHandler = new InternalHandler();
    private static class InternalHandler extends Handler {
        @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实际上就是一个Handler,刚才postResult在发送消息时,带的一个参数MESSAGE_POST_RESULT就在这个InternalHandler里的handleMessage方法中处理了。我们接着看

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

finish这个方法很简单,逻辑也很清晰,如果AsyncTask被取消执行了,那么就回调onCancelled(result),否者继续执行onPostExecute(result),这里我们可以了解到需要停止AsyncTask可以在onCancelled(result)这里做处理了。可以看出,doInBackground的返回结果会传递给onPostExecute方法执行,到这里,整个AsycnTask的工作原理就分析完了,不得不佩服老外写程序的思想,简洁的封装了handler和Thread后,就有了这么一个轻量异步处理任务类!























版权声明:本文为博主原创文章,未经博主允许不得转载。

iOS 一个app跳转另一个app并实现通信(如A跳到B并打开B中指定页面)

功能实现:A跳到B并打开B中指定页面步骤: 首先创建两个项目(项目A,项目B),在项目B中的info.plist文件中添加URL Types,如下图所示:其中URL idenifier是项目B的bun...

安卓圆心进度条CircleProgressView

最近做了一个圆形进度条控件 顺便就把他抽出来哒直接贴出代码了  类中提供了各种颜色的设置 字体大小 已经进度的宽度 加上了进度回调(虽然感觉没啥卵用)  这是自定义的类  就这么一个类咯 ...

Android多线程-AsyncTask工作流程(源码)

AsyncTask的源码是很简单的,看着并不复杂。只是对Handler和ThreadPoolExecutor进行了一下封装。基于api25(7.1)的代码,使用起来也是很简单的,看上个就知道了。一般要...

AsyncTask工作流程源码分析

通过源码了解ASyncTask整个流程 以及线程池的一些基本概念

android开发之源码级分析(系统启动流程 & Handler消息机制 & AsyncTask机制)

All in all,because just begun!

Android AsyncTask 源码详细解析,掌握工作原理和细节

我们常常会在面试中被问及 xx 知识点用法,然后面试官会接着问是否了解其工作原理。无可厚非,我们不能仅仅满足于会用,难道你就不想知道它是如何工作的,不想了解它的源码吗?之前我们在 Android As...

源码解析Android中AsyncTask的工作原理

在之前的博客《Android中AsyncTask使用详解》中我们提到AsyncTask是对Thread和Handler的组合包装,本文将通过解析的方式让大家了解AsyncTask的工作原理。Async...

Android源码分析—带你认识不一样的AsyncTask

转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/17596225 前言 什么是AsyncTask,相信搞过android开发...

Android中AsyncTask的使用与源码分析

Android中AsyncTask的使用与源码分析 在Android中实现异步任务机制有两种方式,Handler 和 AsyncTask。      Handler模式需要为每一个...

Android从源码分析二:AsyncTask异步任务

AsyncTask能够适当地、简单地用于 UI线程。这个类不需要操作线程(Thread)就可以完成后台操作将结果返回UI。 简而言之,AsyncTask也是为了解决 “耗时操作过程中,UI经常需要更...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android基于源码分析AsyncTask的工作流程
举报原因:
原因补充:

(最多只允许输入30个字)