Android开发Android知识Android开发

AsyncTask源码解析

2018-01-31  本文已影响15人  求闲居士

一,前言

今日在使用AsyncTask时,发现对其实现原理又不太记得了,在此再解读一边,以便记忆和使用。

android3.0前的多线程并行执行的版本年代久远就不再分析了,

二,使用

1.场景

在使用一个Thread处理事务,然后使用Handle在UI线程接收处理结果进行后续工作。简单来说就是替代Thread + Handler 的一种方式。

这是我第一次使用AsyncTask的状态,用以实现新线程后台操作和UI更新。如网络请求和数据库操作等都会用到AsyncTask。

但AsyncTask的后台操作耗时也不应该太长,耗时操作还是要使用并发库中的工具类。

2.参数和方法
2.1 参数
private class Test extends AsyncTask<Params, Progress, Result> { ... }

我们继承AsyncTask时,会有三个参数Params, Progress, Result要定义。

2.2 方法
2.3 注意事项

三.解析

解析方式,就从execute方法一步一步走下去。

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

executeOnExecutor则是指定线程执行的方法,可以看出execute是使用默认线程sDefaultExecutor执行后台任务。

3.1 sDefaultExecutor

下面来看看sDefaultExecutor是怎样的,它从表面上看是默认的Executor

//静态成员变量,类共享
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
//静态内部类,类共享为顺序执行提供便利
private static class SerialExecutor implements Executor {
        //mTasks用于保存任务,没执行一次execute插入一条,scheduleNext去除一条
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        //正在执行的任务
        Runnable mActive;

        public synchronized void execute(final Runnable r) {
            //插入任务,被插入的任务将会迭代执行。
            mTasks.offer(new Runnable() {
                public void run() {
                    try {//先执行Runnable
                        r.run();
                    } finally { //再条用scheduleNext执行下一个任务。
                        scheduleNext(); 
                    }
                }
            });
            //如果当前没有正在执行的任务,调用scheduleNext取出任务执行
            if (mActive == null) {
                scheduleNext();
            }
        }
        
        //如果队列有任务,则取交予THREAD_POOL_EXECUTOR执行
        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

对ArrayDeque任务队列的取出,是先进先出的策略,每执行一次execute就是插入mTasks队列一个迭代任务,然后判断当前有无正在执行的任务,确保顺序执行

SerialExecutor是实现顺序执行功能的,真正执行任务的是THREAD_POOL_EXECUTOR线程池。

THREAD_POOL_EXECUTOR的参数就不再分析了,因为SerialExecutor使其相当于单线程在使用,线程池的并发也就派不上
用场了。

3.2 executeOnExecutor
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
            Params... params) {
        //对象创建时默认为PENDING,限制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
        mWorker.mParams = params;
        //默认情况下将mFuture交予上面的sDefaultExecutor执行
        exec.execute(mFuture);

        return this;
    }

onPreExecute在这里最早被执行了,接着sDefaultExecutor开始执行。

那mFuture和mWorker又是什么呢?从params上看doInBackground和mWorker有关,从execute上看doInBackground又和mFuture有关。可以猜测doInBackground在mWorker中调用,而mWorker又在mFuture中调用。

3.3 mFuture和mWorker

还是从exec.execute(mFuture)开始,execute是需要Runnable对象,Runnable接口只有个run,用来执行业务。

public void run() {
        ....
        try {
            //Callable就为mWorker对象
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                //执行了mWorker对象的call方法
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                //调用了finishCompletion方法
                    set(result);
            }
        } finally {
           ....
        }
    }
/**
     * Removes and signals all waiting threads, invokes done(), and
     * nulls out callable.
     */
    private void finishCompletion() {
        // assert state > COMPLETING;
        ....
        done();//在新建mFuture,覆盖了这个方法
        //置空mWorker的引用
        callable = null;        // to reduce footprint
    }

在run方法中,执行了callable.call方法,执行成功后又调用了done方法。下面就来介绍call和done方法的实现。

/**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     */
    public AsyncTask() {
        mWorker = new WorkerRunnable<Params, Result>() {
            //将会在FutureTask的run方法中执行
            public Result call() throws Exception {
            //设置标志位,设置为true后,mFuture中将不会再次调用postResult
                mTaskInvoked.set(true);
                 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //doInBackground在此处被调用
                return postResult(doInBackground(mParams));
            }
        };
        //在创建对象时,传入mWorker作为callable参数,在run中被调用
        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 occured while executing doInBackground()",
                            e.getCause());
                } catch (CancellationException e) {
                    postResultIfNotInvoked(null);
                }
            }
        };
    }
    //当mWorker的call方法被调用后,postResult将不会被调用
    private void postResultIfNotInvoked(Result result) {
        final boolean wasTaskInvoked = mTaskInvoked.get();
        if (!wasTaskInvoked) {
            postResult(result);
        }
    }

由上可知执行顺序:FutureTask.run -> WorkerRunnable.call -> doInBackground -> FutureTask.done。

对于doInBackground的返回结果,则是由postResult处理。

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

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;
            }
        }
    }
//处理返回结果
private void finish(Result result) {
        //如果调用了cancel,则接下来调用onCancelled,否则onPostExecute
        if (isCancelled()) {
            onCancelled(result);//调用了onCancelled方法
        } else {
            onPostExecute(result); //onPostExecute在此处调用
        }
        mStatus = Status.FINISHED;//修改标识
    }

处理结果通过InternalHandler,最后调用了finish方法来处理,而finish方法根据是否调用cancel来决定调用onCancelled还是onPostExecute。

这里封装了一个AsyncTaskResult类来传递结果,原因很简单,handler是静态对象,没法直接拿到当前MyAsyncTask的引用。而我们要把task和result对象同时丢给handler,所以要进行一下封装。

3.4 onProgressUpdate

在上面的InternalHandler中,当接收消息为MESSAGE_POST_PROGRESS时,将会调用onProgressUpdate来更新进度。

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

而这个方法是由publishProgress来发送的。所以在doInBackground中,需要手动调用publishProgress方法来更新进度。

3.5 cancel

前面说到cancel,会影响onCancelled和onPostExecute的调用。它还会影响FutureTask执行的任务。

public final boolean cancel(boolean mayInterruptIfRunning) {
        mCancelled.set(true);
        //FutureTask将会执行cancel,根据mayInterruptIfRunning来决定是否立即停止这个任务
        return mFuture.cancel(mayInterruptIfRunning);
    }
//FutureTask
public boolean cancel(boolean mayInterruptIfRunning) {
        ....
        try {    // in case call to interrupt throws exception
            //如果为false,则不会停止正在执行的任务
            if (mayInterruptIfRunning) {
                try {
                    Thread t = runner;
                    if (t != null)
                        t.interrupt();//停止正在执行的任务
                } finally { // final state
                    UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
                }
            }
        } finally {
            //回调FutureTask的done方法
            finishCompletion();
        }
        return true;
    }

mayInterruptIfRunning为true,FutureTask会告诉线程停止执行这个任务,否则不会停止线程继续执行。

随后执行finishCompletion,而finishCompletion方法中会调用done方法,再清空callable也就是WorkerRunnable对象。

上面分析mWorker的代码中讲过,mFuture.done中执行的postResult,是由mWorker的call方法是否执行决定决定的。如果任务正在执行,则由WorkerRunnable的call方法发送消息执行onCancelled,否则由FutureTask的done发动消息执行onCancelled。

也就是说,mFuture.done方法发送消息,只能是执行cancel且要取消的任务还在队列中。

四 总结

总结下普通的一个执行流程:execute(Params... params) -> executeOnExecutor(sDefaultExecutor, params) -> onPreExecute() -> sDefaultExecutor.execute(mFuture) -> scheduleNext() -> THREAD_POOL_EXECUTOR.execute(mActive) -> FutureTask.run() -> WorkerRunnable.call() -> postResult(doInBackground(mParams)) -> result.mTask.finish(result.mData[0]) -> onPostExecute(result)

我做了个简单的时序图:https://www.processon.com/view/link/5a717790e4b0874437b31e97

AsyncTask.png

其中在FutureTask中
FutureTask.run() -> WorkerRunnable.call() ->
FutureTask.set(V v) -> FutureTask.finishCompletion() -> FutureTask.done() -> AsyncTask.postResultIfNotInvoked(Result result) -> postResult(Result result) -> onCancelled(result);

用流程图或UML画图更直观展示,以后有机会再补充。

五 参考

java 内部类和静态内部类的区别

android多线程-AsyncTask之工作原理深入解析(下)

Android 7.0 AsyncTask分析

上一篇下一篇

猜你喜欢

热点阅读