程序员

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

2018-10-16  本文已影响0人  小浩_w

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

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

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以前是默认并行执行。

上一篇下一篇

猜你喜欢

热点阅读