源码分析AsyncTask

前言: 5月份第一篇博客,第一次以自己的视角去分析源码,先看了大量大牛的文章。

  AsyncTask是android提供我们方便使用异步任务的一个封装类,有了它,我们可以很方便的使用异步操作;但是作为一个合格的开发者,只会用并没有什么意义,我们当然要懂得它是怎么实现的,可以让我们这么方便的使用异步任务。

  废话不多说,让我们从常用方法说起,因为是讨论源码,这些只是后面源码需要调用这些方法,提一下比较好。


AsyncTask4个核心方法:

  1. onPreExecute() :在成功调用execute后执行,用于一些准备操作
  2. doInBackground(Params… params):在onPreExecute()后的WorkerRunnable抽象类的实体类中调用,在执行中可以调用publishProgress(Progress… values)方法来更新进度。
  3. onProgressUpdate(Progress… values):在调用publishProgress后执行,此方法可以用来更新UI。
  4. onPostExecute(Result result):在任务执行结束后调用,如果任务已经结束则不会调用。

  Android3.0之前使用的是并行处理。Android7.0后改为串行处理。这样保证了一个时间段只有一个任务执行。

1.从构造方法开始分析:

  AsyncTask提供了3个构造方法,但最终都会调用参数最长的方法,因为其利用了自身回调的设计。

public AsyncTask() {
//调用下一个构造方法
        this((Looper) null);
    }
 public AsyncTask(@Nullable Handler handler) {
 //调用下一个构造方法
        this(handler != null ? handler.getLooper() : null);
    }    

这样两个构造方法并没有什么实现的逻辑,我们来看看最后一个构造方法:

public AsyncTask(@Nullable Looper callbackLooper) {
   mHandler = callbackLooper == null || callbackLooper ==
   Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);

        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                Result result = null;
          try {  
          //设置了线程的优先级
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//这里调用了doInBackground方法,并且传入了result的值
                    result = doInBackground(mParams);
                    Binder.flushPendingCommands();
                } catch (Throwable tr) {
                    mCancelled.set(true);
                    throw tr;
                } finally {
                //最后调用了postResult方法
                    postResult(result);
                }
                return 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);
                }
            }
        };
    }

这里定义了一个mFuture的FutureTask,FutureTask需要传入一个Callable接口,这里也实现了一个WorkerRunnable抽象类,我们看看这个类怎么定义的:

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

从这里我们可以知道WorkerRunnable是一个静态抽象类,并且实现了Callable接口,即是Callable接口的实体类。

  所以从这里我们知道了mFuture = new FutureTask(mWorker)这里为什么要传入一个mWorker。为什么要定义一个WorkerRunnable类。
  我们从这里也可以发现AsyncTask实现线程异步操作利用的正是多线程实现里的FutureTask+Callable接口这个组合(有不懂的可以看我上一篇博客)。

  我们再来看看mWorker里的call()方法,里面我们发现了doInBackground方法原来是在这里被调用,我们还发现在finally代码块里有一个postResult(result)方法,看下这个方法的实现:

private Result postResult(Result result) {
        @SuppressWarnings("unchecked") 
        //这里用message发消息给handler
        Message message =
        //发送执行完毕消息MESSAGE_POST_RESULT
        getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }

原来这个方法是用一个Message去给Handler发送消息,那既然是发送消息,我们肯定要去看看发了什么消息,我找到Hadler的具体实现位置,还记得构造方法里第一个mHandler的语句吗(我在下面再重新贴出来):

    public AsyncTask(@Nullable Looper callbackLooper) {
        mHandler = callbackLooper == null || callbackLooper == 
         Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);
            ......

实现了方法getMainHandler():

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

这里使用单例设计模式,创建一个单例的InternalHandler类,看看是什么个类:

 private static class InternalHandler extends Handler {
        public InternalHandler(Looper looper) {
            super(looper);
        }

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

终于,我们在这个类中找到了handleMessage方法,原来消息在这里被接收,消息被接收之后,调用finish()方法去完成执行异步任务,看看finish()方法:

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

我们看到这个有一个mStatus变量,这个变量是用来设置当前的状态,现在把状态设置为了Status.FINISHED,执行结束状态。并且我们发现会调用onPostExecute方法。

讲完这些后,我们发现有一个publishProgress没有分析,我们来看看publishProgress方法:

 protected final void publishProgress(Progress... values) {
        if (!isCancelled()) { 
        //同样是发送消息让handler接收
            getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                    new AsyncTaskResult<Progress>
                    (this, values)).sendToTarget();
        }
    }

我们会想起,之前那个InternalHandler类有一个switch语句块,我们看下:

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

我们发现第二个就是接收publishProgress发送的消息,然后执行onProgressUpdate方法。看到这里我们明白了,为什么调用publishProgress就可以执行到onProgressUpdate更新UI进度。

  看到这里不知道你有没有发现,消息里面都传入了一个 AsyncTaskResult类,我们来看下这个类:

private static class AsyncTaskResult<Data> {
        final AsyncTask mTask;
        final Data[] mData;

        AsyncTaskResult(AsyncTask task, Data... data) {
            mTask = task;
            mData = data;
        }
    }

是一个静态类;第一个参数是一个AsyncTask,第二个参数是通过泛型来传入的Data数组mData,类里只有一个构造方法来初始化参数。(因为InternalHandler为静态内部类,所以类中方法不能直接调用)

2.从提交方法execute()接着分析:

  因为使用AsyncTask的使用就只是

new asyncTask().execute();

已经从构造方法分析完了new asyncTask(),那接下来当然要分析execute()方法,我们来看下源码:

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

是调用了一个executeOnExecutor方法,我们接着看:

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方法
        onPreExecute();

        mWorker.mParams = params;
 //执行mFuture
        exec.execute(mFuture);

        return this;
    }

这里先判断异步任务是否已经在执行,不是就设置为正在执行,并且利用sDefaultExecutor线程池来执行mFuture。

我们来看看这个sDefaultExecutor参数的定义:

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

我可以发现sDefaultExecutor是一个SerialExecutor线程池,它是一个串行的线程池,让我们看看它的代码:

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 {
      //这个调用FutureTask的run方法最后调用WorkerRunnable的call方法
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

最后会回到调用FutureTask的run方法然后调用WorkerRunnable的call方法,最后调用postResult方法,之后就是前面的流程了。

最后我们看看scheduleNext()定义的这个线程池THREAD_POOL_EXECUTOR:

private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private 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 BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);

static {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                sPoolWorkQueue, sThreadFactory);
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;
    }

ThreadPoolExecutor的核心线程由CPU的核心数来计算得出。采用的队列是LinkedBlockingQueue,容量为128。

还有就是如果想要使用并行处理,可以使用下面代码:

asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"");

还可以利用这个executeOnExecutor方法传入自定义线的程池:

Executor exec = new ThreadPoolExecutor(......(需要自定义的参数));
asyncTask.executeOnExecutor(exec,"");

这次的AsyncTask源码分析就到这里了,有什么写的错误的地方希望指出,本人能力有限,文章难免有一些错误。


总结一下:

  AsyncTask利用了FutureTask+Callable接口,利用线程池和阻塞队列来实现它的功能。其实AsyncTask就利用到了线程和线程池的知识,源码里还要一些静态内部类,单例设计,Message和Handler进行消息的传送这些知识,代码写的非常好,值得反复细读。

猜你喜欢

转载自blog.csdn.net/weixin_38364803/article/details/80194252