AsyncTask源码分析

作者: TruthKeeper | 来源:发表于2017-03-07 08:55 被阅读57次

    突然发现自己开发其实很少用到AsyncTask⁄(⁄ ⁄•⁄ω⁄•⁄ ⁄)在这里补上对它的源码分析

    初见

    在Android启蒙导师黑马程序员的视频中曾经听到过一句话,AsyncTask:轻量级的线程工具,方便快捷的实现工作线程到主线程的通信。
    在翻看AsyncTask源码时一部分注释如下

    /**
     * <p>AsyncTask enables proper and easy use of the UI thread. This class allows you
     * to perform background operations and publish results on the UI thread without
     * having to manipulate threads and/or handlers.</p>
     *
     * <p>AsyncTask is designed to be a helper class around {@link Thread} and {@link Handler}
     * and does not constitute a generic threading framework. AsyncTasks should ideally be
     * used for short operations (a few seconds at the most.) 
    

    大意呢就是AsyncTask可以允许你在工作线程中发布结果到UI线程,但是它适合短时间操作最多几秒钟,嗨哟,这么傲娇,走了走了,还是滚去用RxJava算了,HandlerThread也行。
    AsyncTask:别看注释吓人,我这样都没被淘汰,亲儿子啊~~
    那我们再留下看看他还有什么话要说(;¬_¬)

    使用

    可以看到AsyncTask需要传入3个泛型参数
    public abstract class AsyncTask<Params, Progress, Result>
    依次代表传入工作线程的参数,进度回调,回调给UI线程的结果,艾玛,都有进度回调,这么一看好像很NB的样子。
    我们随便写个AsyncTask看看

    TestTask task = new TestTask();
    task.execute(1, 2, 3, 4, 5, 6);
    /**
         * 测试
         */
        class TestTask extends AsyncTask<Integer, Integer, String> {
            private static final String TAG = "TestTask";
    
            @Override
            protected void onPreExecute() {
                //预处理(UI线程)
            }
    
            @Override
            protected String doInBackground(Integer... params) {
                //必须实现,异步耗时任务(工作线程)
                StringBuilder sb = new StringBuilder();
                for (int i : params) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    sb.append(i);
                }
                Log.d(TAG, "doInBackground: " + sb.toString());
                return sb.toString();
            }
    
            @Override
            protected void onProgressUpdate(Integer... values) {
                //进度回调(UI线程)
                Log.d(TAG, "onProgressUpdate: " + values[0]);
            }
    
            @Override
            protected void onPostExecute(String s) {
                //回调给UI线程(UI线程)
                Log.d(TAG, "onPostExecute: " + s);
            }
        }
    

    过了一会果然输出了2行日志,进度什么的还是要自己来搞
    doInBackground: 123456
    onPostExecute: 123456

    分析

    那么我们来看看execute这个方法是在怎么启动的

    //UI线程限定
     @MainThread
        public final AsyncTask<Params, Progress, Result> execute(Params... params) {
            return executeOnExecutor(sDefaultExecutor, params);
        }
    
     @MainThread
        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();
    
            mWorker.mParams = params;
            exec.execute(mFuture);
    
            return this;
        }
    

    看到这里,我们有了大概的思路,execute方法内部调用了默认的执行方法来执行,相对状态进行校验过后,将参数赋值后,执行方法,我们接下来先看看参数是在怎么赋值的,
    mWorker.mParams = params;

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

    可以发现mWorker其实就就是简简单单一个实现Callback接口的静态内部类,里面存放参数,那么exec.execute(mFuture);呢,execute传递进去了一个默认的执行规则

    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
    //execute 默认
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    

    其中Executor是一个接口

    public interface Executor {
        void execute(Runnable command);
    }
    

    SerialExecutor,翻译出来叫做串行执行,我们来瞧瞧TA的实现

    private static class SerialExecutor implements Executor {
            //双端队列,可以简单的理解成一个队列
            final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
            //正在运行中的
            Runnable mActive;
    
            public synchronized void execute(final Runnable r) {
                //将一个runnable放置到队列末尾
                mTasks.offer(new Runnable() {
                    public void run() {
                        try {
                            r.run();
                        } finally {
                            //不考虑执行结果如何都会执行下一个任务
                            scheduleNext();
                        }
                    }
                });
                if (mActive == null) {
                    //第一次从这里开始执行任务
                    scheduleNext();
                }
            }
    
            protected synchronized void scheduleNext() {
                //从队列取出一个任务
                if ((mActive = mTasks.poll()) != null) {
                    //真正开始执行
                    THREAD_POOL_EXECUTOR.execute(mActive);
                }
            }
        }
    

    看到这里,敢情SerialExecutor就是THREAD_POOL_EXECUTOR的封装版,保证里面的runnable都是串行执行,名至实归,看到这里,笔者突然发现小小的AsyncTask中蕴含了不少的东西,那么我们完整的看下AsyncTask的构造器和成员变量

    深入

    //API25
    public abstract class AsyncTask<Params, Progress, Result> {
        //手机CPU数目
        private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
        //根据CPU来配置核心线程数目,每个编译版本可能不一样
        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;
        //空线程30s保活
        private static final int KEEP_ALIVE_SECONDS = 30;
        //配置线程池时,给每个线程名字命名
        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());
            }
        };
        //阻塞队列,限长128
        private static final BlockingQueue<Runnable> sPoolWorkQueue =
                new LinkedBlockingQueue<Runnable>(128);
        //线程池的执行
        public static final Executor THREAD_POOL_EXECUTOR;
        //静态代码块,全局都是这个线程池
        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;
        }
    
        public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
        //消息的what
        private static final int MESSAGE_POST_RESULT = 0x1;
        private static final int MESSAGE_POST_PROGRESS = 0x2;
    
        private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
        //回调的Handler
        private static InternalHandler sHandler;
        //实现Callback,存放参数
        private final WorkerRunnable<Params, Result> mWorker;
        //执行的具体方法
        private final FutureTask<Result> mFuture;
        //记录状态
        private volatile Status mStatus = Status.PENDING;
        //高比发下保证原子性操作,记录任务是否取消,是否执行
        private final AtomicBoolean mCancelled = new AtomicBoolean();
        private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
    
        private static class SerialExecutor implements Executor {
            //上文已有,省略。。。
        }
    
        public enum Status {
            //等待执行
            PENDING,
            //执行中
            RUNNING,
            //结束
            FINISHED,
        }
    
    
        public AsyncTask() {
            mWorker = new WorkerRunnable<Params, Result>() {
                public Result call() throws Exception {
                    //任务执行
                    mTaskInvoked.set(true);
                    Result result = null;
                    try {
                        //设置线程的优先级
    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                        //noinspection unchecked
                        //执行方法
                        result = doInBackground(mParams);
                        Binder.flushPendingCommands();
                    } catch (Throwable tr) {
                        mCancelled.set(true);
                        throw tr;
                    } finally {
                        //结果post
                        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);
                    }
                }
            };
        }
    

    每处地方笔者几乎都打上了注释,毕竟我就是那么的贴心,恩(°∀°)ノ,其中有几处细节
    AsyncTask的线程池配置根据手机配置来的,缓冲队列默认是128,也就是说如果有一只4核的手机,那么根据如上API25的配置

    • CPU_COUNT=4
    • CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4)) = 4
    • MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1 = 7

    线程池中最大容纳7个线程,同时处理4个工作线程,满出来的放到BlockingQueue中,也就是128的数量限制,默认还是串行执行,如果工作线程过于密集,不仅会阻塞后续的线程,还有可能抛出RejectedExecutionException异常,被线程池拒绝,至此,前文的AsyncTask的注释提示适合短时间的任务也就揭开了面纱。
    当后台任务完成会调用这个方法返回结果

     private Result postResult(Result result) {
            @SuppressWarnings("unchecked")
            Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                    new AsyncTaskResult<Result>(this, result));
            message.sendToTarget();
            return result;
        }
    
    private static class InternalHandler extends Handler {
            public InternalHandler() {
                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
                        result.mTask.finish(result.mData[0]);
                        break;
                    case MESSAGE_POST_PROGRESS:
                        result.mTask.onProgressUpdate(result.mData);
                        break;
                }
            }
        }
    
    private static class AsyncTaskResult<Data> {
            final AsyncTask mTask;
            final Data[] mData;
    
            AsyncTaskResult(AsyncTask task, Data... data) {
                mTask = task;
                mData = data;
            }
        }
    

    通过InternalHandler来分发消息,然后对应执行mTask的相关回调方法

    总结

    综上所诉,AsyncTask驱动的其实是mFuture,本质也是一个Runnable;进度回调由我们自己调用publishProgress,工作线程限定

        @WorkerThread
        protected final void publishProgress(Progress... values) {
            if (!isCancelled()) {
                getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                        new AsyncTaskResult<Progress>(this, values)).sendToTarget();
            }
        }
    

    一遍源码看下来,AsyncTask其实是将一个异步任务分配到线程池中来执行,完成后通过Handler来分发的一个封装的库,由于默认的执行还是串行的,虽然支持多线程并行,但是不太适合高频的网络请求,适用于一些轻量的IO操作。
    Ps:由于使用过程中带有一些坑,就偷懒不放调用流程图了

    参考:
    AsyncTask和AsyncTaskCompat源码解析
    Android AsyncTask 源码解析

    凡劳苦担重担的人可以到我这里来,我就使你们得安息。 (马太福音 11:28 和合本)

    相关文章

      网友评论

        本文标题:AsyncTask源码分析

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