AsyncTask源码解析

参考资料

鸿洋版AsyncTask
郭霖版AsyncTask
线程池
Android开发艺术探索
Android源码

相关背景知识:

Android消息机制、线程池。

AsyncTask是什么?

(1)AsyncTask是一种轻量级的异步任务类,可以在线程池中执行耗时任务,然后把执行的进度和最终结果传递给主线程并更新UI;AsyncTask封装了Thread和Handler,可以更加方便执行耗时任务,并在主线程中更新UI;
(2)AsyncTask是一个抽象泛型类,提供了Params、Progress和Result三个泛型参数,Params表示参数类型,Progress表示后台任务执行进度的类型;Result表示后台任务结果返回类型;如果不确定传什么参数,那么这三个泛型参数可以用void来代替;

AsyncTask4个核心方法

(1)onPreExecute:在主线程中执行,在异步任务执行之前,此方法可以被调用,一般用于做一些准备工作;
(2)doInBackGround(Params...params),在线程池中执行,用于执行异步任务;params表示异步任务输入参数,在该方法中可以调用publishProgress方法来更新任务进度,该方法会调用到onProgressUpdate中;另外此方法需要将执行结果返回给onPostExcute方法;
(3)onProgressUp0date:在主线程中执行,后台任务执行进度发生改变时此方法被调用;
(4)onPostExcute(Result result):在主线程中执行,result为doInBackgroud返回值;

AsyncTask执行过程

(1)启动方法:new AysncTask().execute();
(2)new AsyncTask()构造方法

    public AsyncTask() {
        mWorker = new WorkerRunnable() {
            //执行FutureTask run方法会调用到此处
            public Result call() throws Exception {
                mTaskInvoked.set(true);

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                Result result = doInBackground(mParams);
                Binder.flushPendingCommands();
                return postResult(result);
            }
        };

        mFuture = new FutureTask(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);
                }
            }
        };
    }

(3)调用AsyncTask.execute()方法

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

其中sDefaultExecutor是SerialExecutor实例代码如下

    private static class SerialExecutor implements Executor {
        //异步任务队列;
        final ArrayDeque mTasks = new ArrayDeque();
        Runnable mActive;
        public synchronized void execute(final Runnable r) {
            mTasks.offer(new Runnable() {  //添加到队列中;
                public void run() {
                    try {
                        r.run();
                    } finally {
                        //执行完上一个任务之后会就行调用scheduleNext();去执行下一个任务;
                        //所以当上一条任务没有执行完,下一个任务是不会执行的;这样AsyncTask中
                        //所有任务都是串行执行的;
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) { //第一次执行时为null;所以会执行scheduleNext();
                //第一次执行时,传入的参数为mFuture,所以执行mFuture的run方法;因为
                第二次再次执行时mActive不为null所以不会再次进入该方法,该方法尽在首日调用时进入;
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext() {
            /*任务队列中有任务时,会将任务放到THREAD_POOL_EXECUTOR线程池中去执行;  
            线程池相关内容请参考相关文章*/
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

其中THREAD_POOL_EXECUTOR为:

    //CORE_POOL_SIZE:为核心线程数量,MAXIMUM_POOL_SIZE最大线程数;
    public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

(4)执行FutureTask run方法:

    public void run() {
        //该方法在线程池中执行;
        if (state != NEW ||
            !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
            return;
        try {
            //在AsyncTask构造方法中初始化FutureTask时,会传入mWorker,mWorker是WorkRunable对象,
            WorkRunable实现Callable接口
            Callable c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    //调用AsyncTask mWorker对象的call方法;
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } finally {
            ...
        }
    }

(5)AsyncTask执行mWorker call方法:

        mWorker = new WorkerRunnable() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                //在此时执行AsyncTask doInBackground方法;
                Result result = doInBackground(mParams);
                Binder.flushPendingCommands();
                执行完毕之后,调用postResult方法;
                return postResult(result);
            }
        };

6.执行AsyncTask postResult方法:

    private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        /*InternalHandler发送MESSAGE_POST_RESULT消息,下一步会执行
        InternalHandler handleMessage对象;Android消息机制请参考相关文章;*/
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult(this, result));
        message.sendToTarget();
        return result;
    }

其中getHandler返回InternalHandler对象,InternalHandler源码如下:

    private static class InternalHandler extends Handler {
        public InternalHandler() {
            //Looper.getMainLooper获取主线程looper,这样
            //handler在收到消息并调用handleMessager时可以切换到主线程;
            super(Looper.getMainLooper());
        }

        @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
                    在收到消息时,调用AsyncTask finish方法;*/
                    result.mTask.finish(result.mData[0]);
                    break;
                case MESSAGE_POST_PROGRESS:
                    /*如果在doInBackgound中执行publishProgress,publishProgress会发送
                    MESSAGE_POST_PROGRESS,这样会调用AsyncTask onProgressUpdate方法,该方法可以
                    在UI线程中更新异步任务的进度;*/
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }

(7)执行AsyncTask finish方法:

  private void finish(Result result) {
      if (isCancelled()) {//如果没有调用cancel方法,该方法返回false;
          onCancelled(result);
      } else {
          //执行onPostExcute方法,这样当前任务执行完毕;然后继续回到SerialExecutor中执行finally
          中的scheduleNext();继续执行下一个任务;
          onPostExecute(result);
      }
      //将mStatus修改为Status.FINISHED,如果两次执行AsyncTask那么执行到executeOnExecutor方法时,会跑出异常;
      mStatus = Status.FINISHED;
  }
其他相关问题:

(1)AsyncTask是否必须在主线程创建并执行?
答:创建:在UI线程和子线程都可以创建AsyncTask;
执行:在主线程中执行AsyncTask是正常流程;所以不会有问题;在子线程中执行AsyncTask:1.由于onPreExecute和启动AsyncTask是在同一个线程,所以只要onPreExecute不操作UI就不会有异常;2.onProgressUpdate:publishProgress会获取InternalHandler,并发送MESSAGE_POST_PROGRESS消息;由于InternalHandler使用的是主线程中的looper,所以在执行Handler.handleMessage()时,已经切换到主线程,所以在子线程执行AsyncTask时,onProgressUpdate是可以操作UI控件的;3.onpostExecute同onProgressUpdate;
结论:在主线程和子线程都可以创建AsyncTask,在子线程(只要onPreExecute不操作UI控件)和主线程
都可以执行AsyncTask;
(2)Android开发艺术探索提到AsyncTask中有两个线程池(SerialExecutor、THEAD_POOL_EXCUTOR),对吗?
答:其中SerialExcutor知识一个线程执行的东西,不是线程池,Android开发艺术探索书写有误;
(3)AsyncTask串行执行还是并行执行?
1.AsyncTask在并发执行多个任务时会发生异常。在3.0以前的系统中还是会以支持多线程并发的方式执行,同一时刻能够运行的线程数为5个,线程池总大小为128。也就是说当我们启动了10个任务时,只有5个任务能够立刻执行,另外的5个任务则需要等待,当有一个任务执行完毕后,第6个任务才会启动,以此类推。而线程池中最大能存放的线程数是128个,当我们尝试去添加第129个任务时,程序就会崩溃。
2,通过源码可以看出现在所有任务被执行时,都是先在SerialExcutor进行排队,执行完上一个任务才会执行下一个任务;所以目前AsyncTask中的任务是串行执行的,通过代码实测,其中排队的任务可以有N多个,尝试20000个任务程序也没有崩溃;
3.如果想并行执行可以executeOnExcutor(AsyncTask.THREAD_POOL_EXECUTOR,new AsyncTask());目的就是跳过SerialExecutor排队流程;
(4)为什么子线程不能更新UI控件?
1.因为UI控件不是线程安全的;
(5)为什么不对UI控件的访问加上锁机制?
1.加上锁之后,访问逻辑变的复杂;
2.锁机制降低UI访问效率;
(6)为什么AsyncTask只能执行一次?
因为执行完成后会将mStatus修改为Status.FINISHED,再次执行到executeOnExecutor方法时,如果mStatus为FINISHED,那么就会抛出异常;

你可能感兴趣的:(AsyncTask源码解析)