AsyncTask介绍及源码执行过程分析

1.概述

在Android中线程是一个很重要的概念,从用途来说,线程分为主线程和子线程,主线程主要去做界面的更新操作,而子线程去做耗时操作,从网络去拉取数据。在Android3.0以后开始,系统要求网络访问必须在子线程中执行,否则会报NetworkOnMainThreadException这个异常,这样做是为了避免在主线程中执行耗时操作而出现ANR异常。

对于一般线程操作,可以使用Thread+Handler,AsyncTask,HandlerThread以及IntentService,后三者的底层实现也是线程,但是他们也有特殊的表现形式,同时也有各自的优点。其中AsyncTask封装了线程池和Handler,本文主要分析下它的使用以及源码执行过程分析。

2.AsyncTask

AsyncTask是一个轻量级的异步任务类,它可以在线程池中执行后台任务,并把执行的进度和最终结果传递给主线程并在主线程中更新UI。

AsyncTask是一个抽象的泛型类,它提供了三个泛型参数Params, Progress, Result。Params是doInBackground的入口参数,Progress表示后台的任务执行进度,Result表示后台的任务返回结果。

这个类的声明如下:

public abstract class AsyncTask < Params, Progress, Result >

它主要提供了4个核心方法,含义如下:

onPreExecute()

任务开始执行之前的操作,异步任务开始之前,它会被调用,主要做任务的准备操作。

doInBackground(Params… params)

在线程池中执行,此方法主要在工作线程中,params是一个入口参数,且是一个可变参数,可以传入多个。在这个方法中,可以通过publishProgress更新任务进度,同时publishProgress会调用onProgressUpdate在主线程中更新进度。这个方法的返回值会传入onPostExecute。

onProgressUpdate(Progress… values)

任务更新操作,后台调用publishProgress,发送一个消息给handler来执行进度更新操作,在主线程中执行。

onPostExecute(Result result)

主线程中执行,异步任务之后,会返回一个Result作为onPostExecute的入口参数。

AsyncTask在具体使用过程中的条件限制:
1)AsyncTask 的类必须在主线程中创建
2)AsyncTask的对象必须在主线程中创建
3)execute方法必须在UI线程中调用
4)不要再程序中直接调用它的方法
5)一个AsyncTask对象只能执行一次,及只能调用一次execute方法,否则会报运行时异常。
6)Android 3.0以前是使用线程池中并行任务,但是在Android 3.0以后,为了出现AsyncTask的并发错误,又采用了一个线程池来串行执行任务。但是我们也可以调用AsyncTask的executeOnExecutor方法来并行执行任务。

3. 执行过程

为了查看它的执行过程,我们可以从execute方法开始分析

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

    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,它的内部调用了executeOnExecutor,onPreExecute()被执行了,而params被封装到了mWorker中,接着exec.execute(mFuture)这个被执行,其中exec是sDefaultExecutor,看下其声明过程

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

我们可以看到SerialExecutor实现了Executor,所以exec.execute就是执行SerialExecutor的execute方法,看下其实现过程:

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

先不分析,看下AsyncTask的构造方法

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

我们可以看到实现了mWorker这个Callable接口,和实例化了mFuture这个类,并将mWorker传递给了mFuture,看下其run方法:

public void run() {
        if (state != NEW ||
            !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } finally {
            // runner must be non-null until state is settled to
            // prevent concurrent calls to run()
            runner = null;
            // state must be re-read after nulling runner to prevent
            // leaked interrupts
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }

这个callable就是mWorker,这段代码也就是说在执行run方法时,实际会调用mWorker的call方法。而刚开始的params参数被封装到了mWorker中,所以最终会在call中被执行。

再来回看SerialExecutor的execute方法,mFuture方法封装的mWorker交给它处理,首先会把FutureTask对象插入到任务队列mTask中并执行,之后如果mActive 没有正在执行的活动,就会调用SerialExecutor 的scheduleNext方法。同时当一个任务执行完毕之后,执行其他任务,直到所有任务被执行完毕,从这一点来看,AsyncTask默认是串行执行的。

刚才在构造方法中看了mWorker的匿名实现方法:

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

首先将mTaskInvoked设为true,表示当前任务已经被执行了,然后执行doInBackground(mParams)将其返回值交给postResult执行,看下其实现过程:

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

上面代码中首先通过getHandler获取一个sHandler,如果我们看其实现过程,可以看见它是一个单例类,这里就不看了。在postResult中,发送一个MESSAGE_POST_RESULT的消息给sHandler(InternalHandler), 看下其处理过程:

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

可以看见MESSAGE_POST_RESULT类型消息会执行result.mTask.finish(result.mData[0])方法,而result.mTask是AsyncTask类型,也就是执行它的finish方法

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

result也就是doInBackground的执行结果返回值,如果任务被取消了执行onCancelled方法,否则执行onPostExecute方法,最后将任务状态改为FINISHED。

如果在doInBackground中调用publishProgress方法,他就会向sHandler发送一个MESSAGE_POST_PROGRESS的消息,而sHandler对于这个消息处理的方法为

result.mTask.onProgressUpdate(result.mData);

也就是执行AsyncTask的onProgressUpdate方法。

到此我们可以看见AsyncTask的几个核心方法都被执行到了,分析也就到此为止了。

4.参考

本文主要参考了《Android开发艺术探索》的线程与线程池这章。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值