AsyncTask源码分析

为什么使用AsyncTask

*异步任务(用Thread)
*主线程和子线程通信(用Handler)
*线程的销毁和创建也是要占用时间的,大量创建线程会导致应用性能降低。(用线程池)

源码分析

1.从构造函数看起

    public AsyncTask() {
        mWorker = new WorkerRunnable<Params, Result>() {
            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<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);
                }
            }
        };
    }

构造函数做了两件事情,第一件是实例化了一个WorkerRunnable,第二件是实例化了一个FutureTask,至于这两个东西有什么用,暂且先放着,等到遇到的时候再分析。

2.异步任务的起点executeOnExecutor

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

在executeOnExecutor方法上有一个@MainThread注解,顾名思义,这个注解表示此方法只能在主线程中调用,同样的还有@UiThread@WorkerThread@BinderThread,都是指定了方法的调用线程。
executeOnExecutor有2+个参数(变长参数),第一个参数是一个接口Executor类型,按照名字来翻译下就是执行器,只有一个方法execute(Runnable command)。其他的参数是任务相关的参数。
方法中,先对AsyncTask当前运行状态判断,如果不是挂起状态,则抛出指定异常。也就是说,这个方法的调用时机必须是当
前的异步任务处于挂起状态才能调用,否则调用会出错。如果是挂起状态下调用此方法,则将当前异步任务状态设置为运行中。而在其他的地方并没有看到将mStatus重新设置为Status.PENDING的地方。也就是说execute只能调用一次。
然后执行onPreExecute()方法,onPreExecute是一个空方法,继承AsyncTask需要在异步任务准备执行前做其他动作时,可以重载此方法。
接着是把异步任务的参数传给构造函数中实例化的WorkerRunnable.然后调用传入的执行器,执行构造函数中实例化的FutureTask。可是这些到底是什么鬼?看不懂啊。算了,接着往下看,还有个execute()方法,看起来和executeOnExecutor有天大的关系。

3.使用默认执行器(Executor)的异步任务的起点execute()

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

代码很简单,就是调用了executeOnExecutor,并且用sDefaultExecutor作为第一个参数。跟着看sDefaultExecutor,可以看到sDefaultExecutor声明时为:private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
同样的还有一个执行器,叫做THREAD_POOL_EXECUTOR,只看名字能猜出个大概,前一个是串行执行的执行器,后一个是线程池的执行器。看注释确认下,也就是前一个是表示任务是按照顺序一个个的执行的,后一个是表示任务可以同步执行的。
分析下THREAD_POOL_EXECUTOR,线程池中最小维护线程数是cup的个数+1,最大维护线程数是2*cup的个数+1,线程队列最大长度为128。这些以后再研究。回头看executeOnExecutor中的exec.execute(mFuture)做了什么,先拿默认的的Executor实例来分析。

4.默认的Executor——SERIAL_EXECUTOR

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

类中创建了一个runnable队列,这个队列是非线程安全的。execute方法前有synchronized关键字,防止多线程造成状态混乱。
execute方法执行,新建一个任务,并将这个任务放入mTasks队列的末尾。runnable的run方法,是执行了传入的runnable的run方法(怎么这么绕),然后判断如果当前没有活动中的任务时,就调用父类的scheduleNext方法。在scheduleNext方法中,如果队头不为空,那么就将对头的runnable成为当前活动的runnable,然后……什么鬼,怎么又到了THREAD_POOL_EXECUTOR……。

5.迈不过的坎THREAD_POOL_EXECUTOR

默认的Executor为SERIAL_EXECUTOR,最后还是调用了THREAD_POOL_EXECUTOR,THREAD_POOL_EXECUTOR是一个ThreadPoolExecutor的实例。通过对ThreadPoolExecutor的分析,知道ThreadPoolExecutor就是一个并发执行的线程池,而通过SERIAL_EXECUTOR中的操作,得到一个串行的线程池。关于ThreadPoolExecutor的源码分析以后再说。

6.AsyncTask中的任务FutureTask

在构造函数中实例化了一个FutureTask实际上就是一个任务,实现了Runnable, Future两个接口,使之成为一个可以取消的任务。
进入FutureTask简单的看了下源码,理解了下,在FutureTask的run方法中mWorker的call方法将被调用。在构造函数中可以看到,AsyncTask的doInBackground方法被调用,执行完毕的返回结果将会传给mFuture的done方法。如何传的呢?

7.果然又见Handler

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

在mWorker的call方法中,最后的返回值是调用了postResult(),而在postResult方法中,直接就是通过handler来传递处理消息的。

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

可以看到处理的消息有两种消息,一种是当前的进度,一种是当前的结果。进入finish方法:

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

如此就明了了:进度更新覆写AsyncTask的onProgressUpdate方法,任务完成覆写onPostExecute方法,任务取消覆写onCancelled方法。

总结

看了这么多发现,AsyncTask就是已经加入线程池管理,通过handler实现了更新UI的异步任务。在AsyncTask的方法setDefaultExecutor上可以看到有@hide注解(据说这个是有版本差异的,没求证),所以我们正常情况下,我们无法利用AsyncTask并发(理论上用反射的方法可以)。

还存在的问题

*ThreadPoolExecutor是怎么实现的?
*FutureTask做了哪些事儿?

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页