在Android - Handler 、AsyncTask(一)一文中,我们提到,为了解决不能阻塞主线程和不能在子线程中更新UI的问题,android提供了handler消息机制。

那么,如果有很多耗时的操作需要进行,并且需要在操作执行完之后或者是在操作过程中更新UI呢?创建很多线程吗?根据我们学过的知识,这个时候可以考虑使用线程池+handler组合的方式了(线程池在本篇博文中暂不总结),而Android已经为我们提供了相应的类来实现我们的需求,这个类就是AsyncTask

二、AsyncTask的实现原理
通常,我们使用AsyncTask的步骤如下: 1、创建一个类myAsyncTask继承AsyncTask A、选择性地复写onPreExecute()方法,该方法在UI线程中被执行,可以做一些初始化的工作,比如在界面上创建一个进度条。 B、(必须)复写doInBackground()方法,将耗时的操作定义在这个方法中,该方法会在onPreExecute()方法执行之后立即执行。 C、选择性地复写onProgressUpdate()方法,(任何时候都可以)在doInBackground()方法中执行publishProgress()方法来调用onProgressUpdate()方法以实现在耗时的操作过程中更新UI D、(必须)复写onPostExecute(Result)方法,利用doInBackground()方法执行完之后返回的结果更新UI。 2、创建myAsyncTask类的实例myAsyncTaskInstance 3、执行myAsyncTaskInstance.execute(Params...)
需要注意的是: a、AsyncTask类的实例只能在UI线程中创建 b、execute方法只能在UI线程中调用 c、不能手动调用onPreExecute()、onPostExecute(Result)、onProgressUpdate()和doInBackground()这几个方法 d、一个AsyncTask的实例只能执行一次execute方法

那么,AsyncTask的具体实现到底是什么样的呢?我们就从execute()方法的调用开始疏理
public final AsyncTask<Params, Progress, Result> execute(Params... params) {return executeOnExecutor(sDefaultExecutor, params);//从AsyncTask.java中可知,sDefaultExecutor为AsyncTask的内部类SerialExecutor的实例:    /*public static final Executor SERIAL_EXECUTOR = new SerialExecutor();    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;*/         }
executeOnExecutor()方法的具体逻辑如下:
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,        Params... params) {//PENDING的API注释为:Indicates that the task has not been executed yet.    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)");        }    }    //Status是AsyncTask的一个内部枚举类,用来标示任务的状态,从上边的代码中可以看到,如果    //mStatus 的值为RUNNING或者FINISHED,则会抛出异常,并且在execute()方法一执行时    //就将mStatus 的值设为了RUNNING,即一个任务只能执行一次    mStatus = Status.RUNNING;    onPreExecute();    mWorker.mParams = params;    exec.execute(mFuture);    return this;}
关于上边第19行的onPreExecute()方法,在AsyncTask类中的定义及注释如下:
/** * Runs on the UI thread before {@link #doInBackground}. */protected void onPreExecute() { //该方法在UI线程中被执行,可以做一些初始化的工作,AsyncTask的子类可以选择性的复写该方法}
那上边的代码中mWorker和mFuture分别代表什么呢?

我们创建myAsyncTask类的实例时,在AsyncTask的构造函数中就已经完成了对mWorker和mFuture两个对象的初始化,mWorker是AsyncTask内部实现了Callable接口的一个类WorkerRunnable的实例:

private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {    Params[] mParams;}
mWorker.mParams = params;这条语句将我们调用execute(Params...)方法时传入的参数赋值给了mWorker的成员变量mParams , mFuture则是FutureTask的一个实例,FutureTask的继承关系如下: public class FutureTask<V> implements RunnableFuture<V> public interface RunnableFuture<V> extends Runnable, Future<V> 即mFuture是Runnable的一个间接子类对象。 关于mWorker和mFuture,暂时讲到此,等后边涉及到时再来详解。
接下来,看exec.execute(mFuture)这条语句 从上文的分析中得知,执行exec.execute(mFuture)会调用SerialExecutor的execute方法, 来看SerialExecutor的完整类定义:
private static class SerialExecutor implements Executor {//需要注意的是,Executor为线程池体系的顶级接口,内部只定义了一个空方法:/*public interface Executor {    *//**     * Executes the given command at some time in the future.  The command     * may execute in a new thread, in a pooled thread, or in the calling     * thread, at the discretion of the {@code Executor} implementation.     *//*    void execute(Runnable command);}*///即SerialExecutor 并不是线程池,它只是复写了execute()方法,可认为它就是一个可执行任务的执行器//定义一个ArrayDeque成员变量,ArrayDeque没有容量限制,是线程不安全的(此处不详解)    final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();//定义一个Runnable类型的临时变量mActive    Runnable mActive;//注意该方法使用了synchronized 关键字进行修饰    public synchronized void execute(final Runnable r) {    //在mTasks队列的尾部插入一个Runnable r        mTasks.offer(new Runnable() {            public void run() {                try {                    r.run();                } finally {                    scheduleNext();                }            }        });        if (mActive == null) {            scheduleNext();        }    }    protected synchronized void scheduleNext() {    //poll()方法从队列的头部检索并删除一个对象,并将检索到的对象返回        if ((mActive = mTasks.poll()) != null) {        //如果poll()方法返回的mActive不为null的话,        //将会调用THREAD_POOL_EXECUTOR.execute(mActive);            THREAD_POOL_EXECUTOR.execute(mActive);        }    }}
关于THREAD_POOL_EXECUTOR:
public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,        TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);//THREAD_POOL_EXECUTOR是AsyncTask类的成员变量,被static和final修饰,是一个线程池对象,//它的各个参数的值分别如下(关于这些值,这里不做解释):private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();private static final int CORE_POOL_SIZE = CPU_COUNT + 1;private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;private static final int KEEP_ALIVE = 1;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());}};private static final BlockingQueue<Runnable> sPoolWorkQueue =new LinkedBlockingQueue<Runnable>(128);
THREAD_POOL_EXECUTOR.execute(mActive): 将Runnable的间接子类对象mFuture交由线程池THREAD_POOL_EXECUTOR处理
那么,我们为什么不直接用THREAD_POOL_EXECUTOR来处理一个任务呢? 事实上,我们在使用AsyncTask时,有两种执行任务的方式可以选择: 1、调用public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,Params... params)方法,指定参数exec为THREAD_POOL_EXECUTOR来执行mFuture任务。 2、直接调用execute(Params... params)方法,这种方式较常用。 在采用第二种方式的情况下,任务会被SerialExecutor的execute方法重新调度之后再由THREAD_POOL_EXECUTOR来进行有序的执行,上文中我们也提到过SerialExecutor的execute方法被synchronized关键字所修饰。这种设计为我们的任务执行提供了更多的选择。 (关于这两种执行方法的区别以及和线程池相关的其他知识,将在其他博文中总结)
根据线程池的相关知识可知,接下来,要执行的就是Runnable的间接子类对象mFuture的run方法了。
同时,上文提到的,AsyncTask的构造函数中mWorker和mFuture这两个对象的初始化的代码也需要贴出来了:
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);            }        }    };}
这里还有一个问题,为什么不把要在后台执行的任务定义在一个runnable对象的run方法中然后再执行THREAD_POOL_EXECUTOR.execute(runnable),而要把任务(doInBackground()方法)定义在mWorker的call方法中,将mWorker作为参数构造出一个mFuture,然后执行execute(mFuture)呢?
我们来看一下FutureTask类的定义:
/** * A cancellable asynchronous computation.  This class provides a base implementation of {@link Future}, * with methods to start and cancel a computation, query to see if the computation is complete, and * retrieve the result of the computation.  The result can only be retrieved when the computation has  * completed; the {@code get} methods will block if the computation has not yet completed.  Once * the computation has completed, the computation cannot be restarted * or cancelled (unless the computation is invoked using {@link #runAndReset}). * <p>A {@code FutureTask} can be used to wrap a {@link Callable} or * {@link Runnable} object.  Because {@code FutureTask} implements * {@code Runnable}, a {@code FutureTask} can be submitted to an * {@link Executor} for execution. */ //一个可取消的异步计算,该类提供了基于Future的一些方法实现,通过这些方法可以开启或退出一个计算,可以 //查看一个计算是否完成并检索计算的结果,如果计算尚未完成,用于检索结果的get方法将会被阻塞,一旦计算 //完成,除非调用runAndReset,否则计算不会被重新启动或者取消,一个FutureTask可以用来包装一个 //Callable或者Runnable对象,因为FutureTask implements Runnable, //一个FutureTask可以被提交给Executor进行执行(只是大致翻译,对这个类有个大概了解)public class FutureTask<V> implements RunnableFuture<V> {//public interface RunnableFuture<V> extends Runnable, Future<V>{}}
可以看出,FutureTask类的存在是为了对一个任务进行包装,为的是能够更好地控制这个任务。 FutureTask类有两个构造函数: 第一个:
public FutureTask(Runnable runnable, V result) {    this.callable = Executors.callable(runnable, result);    this.state = NEW;       // ensure visibility of callable}
Executors类中的callable(runnable, result)方法:
public static <T> Callable<T> callable(Runnable task, T result) {    if (task == null)        throw new NullPointerException();    return new RunnableAdapter<T>(task, result);}
Executors类中的内部类RunnableAdapter:
/** * A callable that runs given task and returns given result */static final class RunnableAdapter<T> implements Callable<T> {   final Runnable task;   final T result;   RunnableAdapter(Runnable task, T result) {       this.task = task;       this.result = result;   }   public T call() {       task.run();       return result;   }}
可以看到,这个构造函数将接收的Runnable task和T result作为参数构造出一个Callable的间接子类对象,并且该对象的call方法中执行的就是task的run方法。然后将这个对象赋给了FutureTask的成员变量callable。

第二个 (也就是我们AsyncTask中的FutureTask走的构造函数):
public FutureTask(Callable<V> callable) {//同样注意泛型    if (callable == null)        throw new NullPointerException();    //将接收的callable赋给FutureTask的成员变量private Callable<V> callable;    this.callable = callable;    this.state = NEW;       // ensure visibility of callable}
和第一个构造函数一样,重点也是在为FutureTask的成员变量callable赋值 接下来, mFuture的run方法:
public void run() {    if (state != NEW ||!UNSAFE.compareAndSwapObject(this, runnerOffset,null, Thread.currentThread()))        return;    try {        Callable<V> c = callable;//将callable赋值给临时定义的allable<V>变量c        if (c != null && state == NEW) {            V result;//定义临时变量V result(泛型)            boolean ran;//定义临时boolean变量ran            try {            //执行c的call()方法,这一步是关键                result = c.call();                //将ran的值设置为true                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类是Runnable的间接子类对象,它复写了run方法,不过,在它的run方法中,真正的任务是在FutureTask的成员变量callable的call方法中执行的,其余代码的作用是为了更好地控制任务的执行,即FutureTask类的注释中提到的。
而AsyncTask中mFuture的创建——mFuture = new FutureTask<Result>(mWorker)——走的是上文提到的FutureTask的第二个构造函数,mWorker是WorkerRunnable类型的实例,关于WorkerRunnable的定义,上文已经列出,WorkerRunnable实现了Callable接口,并复写了call方法。
所以,THREAD_POOL_EXECUTOR.execute(mActive)的执行最终导致mWorker的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));    }};
终于看到了我们的doInBackground()方法了,顺便看一下这个方法 在AsyncTask.java中的定义吧:
/** * Override this method to perform a computation on a background thread. The * specified parameters are the parameters passed to {@link #execute} * by the caller of this task. * This method can call {@link #publishProgress} to publish updates * on the UI thread. * @param params The parameters of the task. * @return A result, defined by the subclass of this task. */ //可以看到,该方法是个空方法,注释也通俗易懂,不翻译了protected abstract Result doInBackground(Params... params);
看到这里,也就明白了AsyncTask是怎样把我们定义到doInBackground()方法中的任务放到后台去执行的了。doInBackground()方法执行完之后,其返回值将作为postResult()方法的参数,来看postResult()方法:
private Result postResult(Result result) {        @SuppressWarnings("unchecked")        Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,                new AsyncTaskResult<Result>(this, result));        message.sendToTarget();        return result;}
该方法的主要逻辑就是: 创建一条消息 what值为MESSAGE_POST_RESULT,obj值为new AsyncTaskResult<Result>(this, result)) ),并且发送出去。 sHandler是AsyncTask的成员变量private static final InternalHandler sHandler = new InternalHandler(); InternalHandler是AsyncTask的内部类, AsyncTaskResult也是AsyncTask的内部类 :
private static class AsyncTaskResult<Data> {//同样需要注意泛型        final AsyncTask mTask;        final Data[] mData;        AsyncTaskResult(AsyncTask task, Data... data) {            mTask = task;            mData = data;        }}
代码比较简单,需要发送的消息的obj值就是一个AsyncTaskResult对象,其成员变量final AsyncTask mTask的值为this,成员变量final Data[] mData的值则是doInBackground()方法的返回值。消息创建好,并且发送出去了,我们来看一下消息的处理:
private static class InternalHandler extends Handler {    @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})    @Override    public void handleMessage(Message msg) {    //先取得AsyncTaskResult 类型的消息的obj--result        AsyncTaskResult result = (AsyncTaskResult) msg.obj;        switch (msg.what) {            case MESSAGE_POST_RESULT:            //接收到上文中的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;        }    }}
消息处理方式为 result.mTask(即该AsyncTask对象)的finish方法(),参数为result.mData[0](即doInBackground()方法的返回值),来看finish方法()的具体逻辑:
private void finish(Result result) {    if (isCancelled()) {        onCancelled(result);    } else {    //如果任务没有退出,则执行onPostExecute(result)方法        onPostExecute(result);    }    mStatus = Status.FINISHED;}
再来看onPostExecute(result)方法的定义:
/**      * <p>Runs on the UI thread after {@link #doInBackground}. The * specified result is the value returned by {@link #doInBackground}.</p> * <p>This method won't be invoked if the task was cancelled.</p> * @param result The result of the operation computed by {@link #doInBackground}. */ //注释同样比较简单,不做翻译了 @SuppressWarnings({"UnusedDeclaration"})protected void onPostExecute(Result result) { }
复写onPostExecute()方法利用doInBackground(Params...)方法的返回值更新UI的流程也梳理清楚了
现在来分析一下,如果我们在doInBackground()方法中执行publishProgress()方法来更新UI的话,代码的执行逻辑又是什么样的? publishProgress()方法的定义如下:
 /**  * This method can be invoked from {@link #doInBackground} to  * publish updates on the UI thread while the background computation is  * still running. Each call to this method will trigger the execution of  * {@link #onProgressUpdate} on the UI thread.  *  * {@link #onProgressUpdate} will note be called if the task has been  * canceled.  *  * @param values The progress values to update the UI with.  */  //后台计算正在进行时可以在doInBackground()方法中调用此方法  //每一次调用这个方法都会导致onProgressUpdate()方法在UI线程中被执行  //接收的参数类型为AsyncTask<Params, Progress, Result>接收的泛型类型Progressprotected final void publishProgress(Progress... values) {     if (!isCancelled()) {         sHandler.obtainMessage(MESSAGE_POST_PROGRESS,                 new AsyncTaskResult<Progress>(this, values)).sendToTarget();     }}
publishProgress()方法和我们上边讲到过的postResult()方法一样,主要逻辑都是创建一条消息并且发送出去。只是在这里,消息的what值是MESSAGE_POST_PROGRESS,消息的obj值为new AsyncTaskResult<Progress>(this, values),消息的处理:
public void handleMessage(Message msg) {    //先取得AsyncTaskResult 类型的消息的obj--result    AsyncTaskResult result = (AsyncTaskResult) msg.obj;    switch (msg.what) {     ... ...     //接收到上文中的MESSAGE_POST_PROGRESS消息后的处理逻辑为:    case MESSAGE_POST_PROGRESS:        result.mTask.onProgressUpdate(result.mData);        break;    }}
和wha t值为MESSAGE_POST_RESULT的消息的处理类似,直接看onProgressUpdate()方法的定义:
/** * Runs on the UI thread after {@link #publishProgress} is invoked. * The specified values are the values passed to {@link #publishProgress}. * @param values The values indicating progress. */ //在publishProgress()方法被调用之后,在UI线程中执行@SuppressWarnings({"UnusedDeclaration"})protected void onProgressUpdate(Progress... values) {//空方法}

至此,AsyncTask的实现原理基本清楚了, onPreExecute()、doInBackground()、publishProgress()、onProgressUpdate()和onPostExecute(Result)这几个方法在一次AsyncTask任务执行过程中所扮演的角色也明了了
还有两个主要问题: 1、AsyncTask使用线程池+handler组合的方式,AsyncTask的缺陷或者说它的灵活使用主要也是在线程池上。关于这方面,需要另写博文作总结。 2、关于FutureTask类是怎样对callable的call方法(任务)进行控制的,还有很多细节没有搞清楚。

更多相关文章

  1. Android开发全程记录(十四)——Android显示gif动画的方法
  2. android中多选框bug之getCheckItemIds()
  3. Android(安卓)HandlerThread 的使用及其Demo
  4. Android小项目————聊天室(网络编程篇)
  5. Handler入门及操作
  6. Android(安卓)进阶学习:Android视图状态及重绘流程分析,带你一步步
  7. android 手把手教你打造万能的ListView GridView的适配器
  8. Android(安卓)自定义Gallery浏览图片
  9. 一个 Android(安卓)任务队列的实现

随机推荐

  1. 网站关键词规划和布局
  2. 一句话次导航相关问题
  3. 301转向有哪些用途?
  4. 网站导航如何SEO优化?
  5. Flex布局案例
  6. 网站优化,什么是四处一词?
  7. 网页内容是写给谁看的?写网页内容需要注意
  8. 表单制作和选择器
  9. 如何判断一个关键词的竞争性?
  10. 如何挖掘网站长尾关键词?