美文网首页
AsyncTask源码学习总结

AsyncTask源码学习总结

作者: 泠牙 | 来源:发表于2020-06-18 11:44 被阅读0次

    前言

    AsyncTask作为Android常用的异步消息机制,内部核心原理其实就是Handler。本小记不对AsyncTask基本使用作介绍,学习了AsyncTask的源码,拜读郭神文章Android AsyncTask完全解析,带你从源码的角度彻底理解. ,趁热来一发,呸,作文以记之。基于android-28。

    先贴一张复习图


    流程概要

    开搞

    1、构造方法

    AsyncTask task=new AsyncTask()

    写在前头
    总共就三步:

    • 创建Handler对象
    • 创建WorkerRunnable对象
    • 创建FutureTask对象

    WorkerRunnable是何物,继承于Callable,内置call方法,浅尝辄止~
    FutureTask是何物,继承于Runnable,内置run方法,且引用了WorkerRunnable对象,什么作用暂且不谈,先mark~

    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);
                        //noinspection unchecked
                        result = doInBackground(mParams);
                        Binder.flushPendingCommands();
                    } catch (Throwable tr) {
                        mCancelled.set(true);
                        throw tr;
                    } finally {
                        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);
                    }
                }
            };
        }
    

    2、执行

    task.execute(params);

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

    默认执行方法的本质是调用了

    executeOnExecutor(Executor exec, Params... params)//其第一个参数为线程池对象

    不看源码,先总结executeOnExecutor核心步骤

    • 执行onPreExecute(),也就很好地说明了onPreExecute在任务启动前执行
    • 赋值params给WorkerRunnable对象,也就相当于丢到了FutureTask里(因为他们有PY交易关系)
    • 线程池启动FutureTask
      这里有两个重点,线程池对象和FutureTask对象,源码里sDefaultExecutor是默认的线程池对象
        public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
        private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    

    然后贴出executeOnExecutor部分代码

     @MainThread
        public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
                Params... params) {
           ...ignore...
            onPreExecute();
    
            mWorker.mParams = params;
            exec.execute(mFuture);
    
            return this;
        }
    

    3、默认线程池sDefaultExecutor

    sDefaultExecutor是静态内部类SerialExecutor的一个实例,不看源码直接总结其execute方法

    • 将任务加入队列->offer
    • 出列任务->poll,如果还有任务,则让另一个小弟来执行任务->THREAD_POOL_EXECUTOR.execute
      说白了sDefaultExecutor它就是个甩锅的,棵棵
        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 {
                            r.run();
                        } finally {
                            scheduleNext();
                        }
                    }
                });
                if (mActive == null) {
                    scheduleNext();
                }
            }
    
            protected synchronized void scheduleNext() {
                if ((mActive = mTasks.poll()) != null) {
                    THREAD_POOL_EXECUTOR.execute(mActive);
                }
            }
        }
    

    另一个小弟THREAD_POOL_EXECUTOR也是线程池对象,暂不深究,反正接下来的动作是执行于子线程中,啊 仿佛闻到了doInBackground的香气。最终要执行FutureTask.run,来了,FutureTask终于来了

    4、FutureTask&WorkerRunnable

    直接干核心run方法,其实里面就主要是callable.call(),callable对象哪里来,当然是那位有点♂哲学关系的WorkerRunnable兄弟,直接进入WorkerRunnable.call()一看究竟

    FutureTask.run部分代码,c即callable实例

    public void run() {
           ...ignore...
            try {
                        result = c.call();
                        ran = true;
                    } catch (Throwable ex) {
                        result = null;
                        ran = false;
                        setException(ex);
                    }
            } finally {
              ...ignore...
            }
        }
    

    上面创建AsyncTask构造方法时,也创建了WorkerRunnable。
    先给call方法作个总结:

    • 设置线程优先级
    • 执行doInBackground
    • 结束后执行postResult
    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 {
                        postResult(result);
                    }
                    return result;
                }
            };
    

    其中doInBackground就是我们很熟悉的,需要重写的抽象函数
    进入postResult(result),发现了handler的踪迹

      private Result postResult(Result result) {
            @SuppressWarnings("unchecked")
            Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                    new AsyncTaskResult<Result>(this, result));
            message.sendToTarget();
            return result;
        }
    

    进入getHandler,层层上翻,发现这里的handler对象是InternalHandler是示例

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

    且看InternalHandler

    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里有两个what,一个是MESSAGE_POST_RESULT即上面postResult发送的,进入.mTask.finish,任务终于收网了,若中途被取消则执行onCancelled(result),否则执行熟悉的 onPostExecute(result)

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

    handleMessage的空一格what,MESSAGE_POST_PROGRESS很显然是更新进度,调用熟悉的onProgressUpdate,在哪里发送呢?必须是publishProgress

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

    补充

    任务调度的默认线程池是SerialExecutor

      public synchronized void execute(final Runnable r) {
                mTasks.offer(new Runnable() {
                    public void run() {
                        try {
                            r.run();
                        } finally {
                            scheduleNext();
                        }
                    }
                });
                if (mActive == null) {
                    scheduleNext();
                }
            }
    

    分析其代码,执行完一个任务后,在finally进行下一个任务的检查,当有多个任务

            new MyAsyncTask("AsyncTask#1").execute("");  
            new MyAsyncTask("AsyncTask#2").execute("");  
            new MyAsyncTask("AsyncTask#3").execute("");  
            new MyAsyncTask("AsyncTask#4").execute("");  
            new MyAsyncTask("AsyncTask#5").execute(""); 
    

    那么
    AsyncTask是默认串行工作的(依次排队挨打)
    如果不需要考虑并发带来的问题,可以
    自定义线程池对象,调用executeOnExecutor达到并行效果(一排同时挨打)

    END

    相关文章

      网友评论

          本文标题:AsyncTask源码学习总结

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