美文网首页程序员
android 源码分析(五AsyncTask机制详解)

android 源码分析(五AsyncTask机制详解)

作者: 小浩_w | 来源:发表于2018-10-16 12:19 被阅读0次

    AsyncTask机制详解

    AsyncTask用法回顾

    AsyncTask类主要用到的几个内部回调函数有:doInBackground()、onPreExecute()、onPostExecute()、onProgressUpdate()。正是这几个回调函数构成了AsynTask类的使用逻辑结构。
    注意:每个AsyncTask子类必须至少复写doInBackGround()方法。

    函数名
    解释

    onPreExecute()
    准备运行(该回调函数在任务被执行之后立即由UI线程调用。这个步骤通常用来完成在用户UI上显示进度条等相关操作)。

    doInBackground(Params...)
    正在后台运行(该回调函数由后台线程在onPreExecute()方法执行结束后立即被调用。通常在这里执行耗时的后台计算。计算的结果必须由该函数返回,并被传递到onPostExecute()中处理。在该函数内也可以使用
    publishProgress()来发布进度值,这些进度值将会在onProgressUpdate()中被接收并发布到UI线程)。

    onProgressUpdate(Progress...)
    进度更新(该函数由UI线程在publishProgress()方法调用完后被调用,一般用于动态地更新一个进度条)。

    onPostExecute(Result )
    完成后台任务(当后台计算结束后被调用,后台计算的结果会被作为参数传递给这一函数)。

    函数回调关系:


    image.png

    通过上方函数调用关系,我们可以总结出一些数据传递关系。如下:

    1. execute( )向doInBackground( )传递数据。
    2. doInBackground( )的返回值会传递给onPostExecute( )。
    3. publishProgress( )向progressUpdate( )传递。

    为了调用关系明确及安全,AsyncTask类在继承时要传入3个泛型:

    public class MyAsyncTask extends AsyncTask<Params, Progress, Result>
    

    • 第一个泛型对应execute( )向doInBackground( )传递的数据类型。

    • 第二个泛型对应publishProgress( )向progressUpdate( )传递的数据类型。

    • 第三个泛型对应doInBackground( )的返回值类型,此返回值将传递给onPostExecute( )方法。

    AsyncTask运行机制梳理

    AsyncTask在调用execute方法后,任务开始执行:

    frameworks\base\core\java\android\os\AsyncTask.java

    ……
    private static final ThreadPoolExecutor sExecutor = 
    new ThreadPoolExecutor(CORE_POOL_SIZE,MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);
     
      ……
     
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
            // 一个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.mParams = params;
            sExecutor.execute(mFuture);
     
            return this;
        }
    

    从这段代码我们可以得出以下结论:

      1. 一个AsyncTask任务只能被执行一次,不能重复execute
      1. 调用AsyncTask的execute方法时,实际上是调用了线程池Executor的execute方法

    Executor的execute方法应该接收的是一个Runnable对象,AsyncTask代码中,我们传递的是一个mFuture,那么这个mFuture是什么呢?

    frameworks\base\core\java\android\os\AsyncTask.java

    ……
        private final WorkerRunnable<Params, Result> mWorker;
    private final FutureTask<Result> mFuture;
    ……
    public AsyncTask() {
            mWorker = new WorkerRunnable<Params, Result>() {
                public Result call() throws Exception {
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    return doInBackground(mParams);
                }
            };
     
            mFuture = new FutureTask<Result>(mWorker) {
                @Override
                protected void done() {
                    Message message;
                    Result result = null;
     
                    ……
                    result = get();
                    ……
     
                    message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
                            new AsyncTaskResult<Result>(AsyncTask.this, result));
                    message.sendToTarget();
                }
            };
        }
    

    在AsyncTask的构造方法中,分别初始化了一个WorkerRunnable的对象mWorker,以及一个FutureTask的对象mFuture。我们先从mFuture开始,看看这两个做了些什么。

    libcore\luni\src\main\java\java\util\concurrent\FutureTask.java

    public class FutureTask<V> implements RunnableFuture<V>
    

    libcore\luni\src\main\java\java\util\concurrent\RunnableFuture.java

    public interface RunnableFuture<V> extends Runnable, Future<V> {
        void run();
    }
    

    从上面2个类,我们可以得知,FutureTask实际上是实现了Runnable接口和Future接口的一个类,因此当执行”sExecutor.execute(mFuture);”时,也一定是执行的mFuture中的run方法。FutureTask是一个增强版的Runnable,他除了Runnable还实现了Future接口,Future接口又是做什么的?

    libcore\luni\src\main\java\java\util\concurrent\Future.java

    public interface Future<V> {
       
        boolean cancel(boolean mayInterruptIfRunning);
     
        boolean isCancelled();
        
        boolean isDone();
        
    V get() throws InterruptedException, ExecutionException;
     
        V get(long timeout, TimeUnit unit)
            throws InterruptedException, ExecutionException, TimeoutException;
    }
    

    简单来说,Future接口就是定义任务取消、是否取消,是否完成、获取结果的一个接口。

    既然知道了mFuture是一个FutureTask,即是一个增强版的Runnable,那么线程池Executor必然也是通过执行其run方法来实现相应的逻辑的,我们来看一下FutureTask的run方法做了什么:

    libcore\luni\src\main\java\java\util\concurrent\FutureTask.java

    private final Sync sync;    
        ……
        public FutureTask(Callable<V> callable) {
            if (callable == null)
                throw new NullPointerException();
            sync = new Sync(callable);
    }
    ……
    public void run() {
            sync.innerRun();
    }
    ……
    

    由代码可知,FutureTask的run方法实际上是调用了Sync类的innerRun方法,而Sync是在FutureTask构造方法中进行的初始化,那么回忆一下AsyncTask构造方法初始化的过程,我们在构建mFuture对象的时候传递了一个WorkerRunnable的对象mWorker:

    frameworks\base\core\java\android\os\AsyncTask.java

    ……
        private final WorkerRunnable<Params, Result> mWorker;
    private final FutureTask<Result> mFuture;
    ……
    public AsyncTask() {
            mWorker = new WorkerRunnable<Params, Result>() {
                public Result call() throws Exception {
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    return doInBackground(mParams);
                }
            };
     
            mFuture = new FutureTask<Result>(mWorker) {
                ……
            };
        }
    

    mWorker是WorkerRunnable的一个子类,并实现了其call()方法,在这个call()方法中,我们看到了一个很关键的代码“return doInBackground(mParams);”,因此可以猜想,最终实际运行在线程池中的逻辑,实际上是这个mWorker的call()方法。

    那么WorkerRunnable又是什么呢?

        private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
            Params[] mParams;
        }
    

    libcore\luni\src\main\java\java\util\concurrent\Callable.java

    public interface Callable<V> {
        V call() throws Exception;
    }
    

    由代码可知,WorkerRunnable是Callable<V>接口的一个子类,他只有一个抽象方法:call方法,这个方法是有返回值的,他返回一个泛型V。
    带入到我们的实际代码逻辑中,在我们的mWorker中,这个call方法返回了我们doInBackground方法执行的结果。

    知道了mWorker是什么,我们返回来看FutureTask的对象mFuture中的逻辑:

    libcore\luni\src\main\java\java\util\concurrent\FutureTask.java

    private final Sync sync;    
        ……
        public FutureTask(Callable<V> callable) {
            if (callable == null)
                throw new NullPointerException();
            sync = new Sync(callable);
    }
    ……
    public void run() {
            sync.innerRun();
    }
    ……
    

    它将mWorker这个Callable<V>的子类作为参数,初始化了一个内部类Sync对象,并在run方法中调用了这个Sync对象的innerRun方法。
    我们来看看Sync是什么:

    private final class Sync extends AbstractQueuedSynchronizer {
            ……
            private final Callable<V> callable;
            
    private V result;
            ……
     
            Sync(Callable<V> callable) {
                this.callable = callable;
            }
            ……
     
    void innerRun() {
                ……
                if (getState() == RUNNING) { // recheck after setting thread
                    V result;
                    try {
                        result = callable.call();
                    } catch (Throwable ex) {
                        setException(ex);
                        return;
                    }
                    set(result);
                } 
                ……
            }
     
            ……
        protected void set(V v) {
            sync.innerSet(v);
    }
     
    void innerSet(V v) {
        ……
        result = v;
        releaseShared(0);
        done();
        return;
          
    }
    }
    

    Sync对象的innerRun方法调用了“result = callable.call();”,并将得到的result最终通过innerSet方法进行了赋值,最终走到了“done()”方法。

    Callable实际上就是我们的WorkerRunnable对象mWorker,这个call方法,实际上就是我们的mWorker的call方法:

    mWorker = new WorkerRunnable<Params, Result>() {
                public Result call() throws Exception {
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    return doInBackground(mParams);
                }
            };
    

    这个call方法中,我们实际上调用了doInBackground方法,并得到了这个方法运行的结果:result。

    doInBackground方法运行结束后,我们通过set方法,最终调用到了innerSet方法,在这innerSet方法中,我们最终调用了FutureTask 的对象mFuture 的done方法:

    mFuture = new FutureTask<Result>(mWorker) {
               @Override
               protected void done() {
                   Message message;
                   Result result = null;
    
                   ……
                   result = get();
                   ……
    
                   message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
                           new AsyncTaskResult<Result>(AsyncTask.this, result));
                   message.sendToTarget();
               }
           };
    

    我们看到done方法通过一个sHandler对象发送了一个Message,看下这个sHandler对象的handleMessage方法做了什么:

    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;
                    case MESSAGE_POST_CANCEL:
                        result.mTask.onCancelled();
                        break;
                }
            }
        }
    

    可以看到,在what = MESSAGE_POST_RESULT的时候,他执行了:
    result.mTask.finish(result.mData[0]);
    这个finish方法其实调用的是当前这个AsyncTask的finish方法,这个finish方法中,调用了我们的onPostExecute方法,且因为是通过Handler发消息来调用的,因此这个onPostExecute方法当前运行到了主线程。代码如下:

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

    因此,由上方代码得到结论:

    1. onPreExecute():UI线程执行。在execute(Params... params)被调用后立即执行,一般用来在执行后台任务前的一些初始化操作

    2. doInBackground(Params... params):子线程执行。在onPreExecute()完成后加入到线程池等待执行,用于执行耗时操作,此方法将接收到execute传递的参数。任务执行完毕,返回结果。

    3. onPostExecute(Result result):UI线程执行。当后台操作结束时,此方法将会被调用,doInBackground返回的Result将做为参数传递到此方法中,可以执行收尾操作。

    AsyncTask跟Handler谁更轻量

    AsyncTask实际上是线程池 + Handler的结合,使用起来是AsyncTask更方便一些,但是使用时还是Handler更轻量一些。
    细节

    AsyncTask在3.0以后改为默认串行执行了,3.0以前是默认并行执行。

    相关文章

      网友评论

        本文标题:android 源码分析(五AsyncTask机制详解)

        本文链接:https://www.haomeiwen.com/subject/cwaczftx.html