AsyncTask源码浅析

原创 2015年11月19日 19:21:37

在开发的过程中我们如果想进行一些耗时的操作不能直接在UI线程中进行,除了使用Handler机制来进行异步消息处理,Android还给我们提供了一个非常方便的类AsyncTask来进行异步操作,在这篇文章中只对AsyncTask的源码进行一下梳理,如果对AsyncTask的使用还不太熟悉的可以先看一下API的使用方法。

我们往往是定义一个类继承AsyncTask,然后创建出这个类的实例,而后调用execute方法来执行任务,我们就从这里入手来分析源码,首先是构造方法:

 /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     */
    public AsyncTask() {
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                return postResult(doInBackground(mParams));
            }
        };

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

首先看一下代码的注释,告诉我们这个构造器必须在UI线程中进行调用,这个在后面会给出分析。构造方法很简单,分别对创建出了WorkerRunnable和FutureTask对象并将其保存起来。先看看WorkerRunnable是什么东西:

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

实现了Callable接口(可以简单的将Callable对象看做一个执行run方法时有返回值的Runnable对象,只不过在Callable中改名叫call方法),是一个抽象类,在构造函数中重写了call方法,暂时先不用考虑里面的逻辑,后面会进行分析。

再看FutureTask类,它的构造方法中接受了一个Callable参数,也就是我们刚刚创建出来的WorkerRunnable对象,看一下它的方法列表不难找到一个比较熟悉的方法,run方法,我们进入看一下:

public void run() {
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         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对象的call方法。

构造函数已经简单的分析完了,现在来看一下我们经常调用的execute方法:

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

可以看到,它只是简单的调用了另一个方法,但是出现了一个没有见过的参数sDefaultExecutor,来看一下这个参数是什么:

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

/**
     * An {@link Executor} that executes tasks one at a time in serial
     * order.  This serialization is global to a particular process.
     */
    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

从注释中可以看出这是一个一次只能执行一个任务的线程池,并且这是一个在进程范围内公用的池,看一下它的定义:

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

代码不是很多,首先在线程池中维护了一个双端队列的实例,并且在线程池的execute方法中并没有执行传入的Runnable对象,而是将它用另一个新创建的Runnable对象包装起来放到队列的尾部。显然,在第一次调用execute方法的时候mActive对象一定是null,这个时候会调用scheduleNext方法将队列中的元素拿出来,并且使用THREAD_POOL_EXECUTOR来执行它,看一下THREAD_POOL_EXECUTOR的代码:

 /**
     * An {@link Executor} that can be used to execute tasks in parallel.
     */
    public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

只是创建了一个固定规格和模式的线程池,这里不是分析的重点就不去深入它了。在执行完成后可以看到无论如何都会执行到SerialExecutor中execute方法的finally语句中,在这里又调用了scheduleNext进行重复的工作。通过上面的分析也就不难理解注释中说明的一次只能执行一个任务,虽然没有继续分析,但是可以猜想出AsyncTask的任务是由SerialExecutor进行分配,并且由于它是static的,在同一个进程内所有的AsyncTask中的任务都会放入到这个类的队列中按顺序执行。

接着回到AsyncTask的execute方法中,调用了executeOnExecutor方法,进入看一下:

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

在这里可以看到熟悉的onPreExecute方法被调用了,由于前面的注释中说过,AsyncTask类对象的创建必须是在主线程中执行的,所以onPreExecute方法的执行也是在主线程中的。而后将传入的参数赋给了mWorker对象中的数组,使用传入的线程池对mFuture进行执行,因为传入的参数是sDefaultExecutor,所以执行的逻辑跳转回了SerialExecutor的execute方法,而后在线程池中执行了mFuture的run方法。根据我们前面的分析它的run方法调用了mWorker的call方法,那么call方法是在哪里实现的呢,没错,在构造函数中:

 public Result call() throws Exception {
                mTaskInvoked.set(true);

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                return postResult(doInBackground(mParams));
            }

在这里执行了doInBackground方法,这个方法应该很熟悉了,它是一个抽象的方法,也是每次都要求我们必须进行重写的。这里由于执行过程还是在线程池中进行的,所以避免了在UI线程中进行耗时操作。方法执行完成后将返回值作为参数传递给了postResult方法,进入看一下:

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

在这里面看到了很熟悉的代码,Handler机制,那么这个Handler是在哪创建的呢,

private static final InternalHandler sHandler = new InternalHandler();

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

很显然Handler类是静态的,在类加载的时候就会初始化这个类,现在回过头再来想一下刚才提到的AsyncTask一定要在UI线程中加载的问题,如果不在UI线程中进行加载,那么Handler自然也就不在UI线程中,那么onProgressUpdate方法和onPostExecute方法中也就不能执行更新UI的操作了。

继续看postResult方法,很简单,就是给Handler发了一个消息并且传了一个参数,而Handler调用了AsyncTask的finish方法用到了这个参数,下面是finish方法:

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

在任务被取消时调用onCancelled方法回调,不然就调用我们熟悉的onPostExecute方法。而在Handler的handleMessage中还有一个接收项,它回调了我们常用的onProgressUpdate方法,找一下这个标记(MESSAGE_POST_PROGRESS)是怎样传入的,不难找到publishProgress方法:

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

这也正是我们在doInBackground中经常使用的。



版权声明:本文为博主原创文章,未经博主允许不得转载。

Android AsyncTask完全解析,带你从源码的角度彻底理解

Android AsyncTask完全解析,带你从源码的角度彻底理解 分类: Android疑难解析2013-10-11 08:35 757人阅读 评论(7) 收藏 举报 Andr...
  • pi9nc
  • pi9nc
  • 2013年10月11日 19:59
  • 7060

Android AsyncTask完全解析,带你从源码的角度彻底理解

我们都知道,Android UI是线程不安全的,如果想要在子线程里进行UI操作,就需要借助Android的异步消息处理机制。之前我也写过了一篇文章从源码层面分析了Android的异步消息处理机制,感兴...
  • sinyu890807
  • sinyu890807
  • 2013年10月11日 08:35
  • 97105

Android应用AsyncTask处理机制详解及源码分析

【工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处,尊重分享成果】1 背景Android异步处理机制一直都是Android的一个核心,也是应用工程师面试的一个知...
  • yanbober
  • yanbober
  • 2015年05月28日 16:02
  • 8160

源码解析Android中AsyncTask的工作原理

在之前的博客《Android中AsyncTask使用详解》中我们提到AsyncTask是对Thread和Handler的组合包装,本文将通过解析的方式让大家了解AsyncTask的工作原理。Async...
  • sunqunsunqun
  • sunqunsunqun
  • 2016年02月17日 23:03
  • 9575

AsyncTask源码浅析

AsyncTask是Android的异步类……恩,大家应该都知道,直接分析吧。开始之前如果对Android的Callable,Future不了解的话可以先看看这篇文章 Java并发编程:C...
  • yuanjize1996
  • yuanjize1996
  • 2016年06月24日 15:34
  • 296

读AsyncTask源码之浅析

带着如下几个问题来阅读AsyncTask源码(Android6.0):         1、AsyncTask只能在UI线程创建?                 2、AsyncTask基于线程池和H...
  • json_it
  • json_it
  • 2017年04月21日 10:20
  • 136

Android多线程(二)AsyncTask源码分析

AsyncTask的基本用法这里就不在赘述了,基本是个安卓开发者就会。 1.android 3.0以前的 AsyncTask private static final int CORE_POOL_SI...
  • itachi85
  • itachi85
  • 2015年04月14日 18:45
  • 3222

Android AsyncTask 源码解析(张鸿洋版)

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38614699,本文出自:【张鸿洋的博客】1、概述相信大家对AsyncTask都不...
  • whocases
  • whocases
  • 2017年01月09日 15:12
  • 444

Android源码分析—带你认识不一样的AsyncTask

转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/17596225 前言 什么是AsyncTask,相信搞过android开发...
  • singwhatiwanna
  • singwhatiwanna
  • 2013年12月27日 02:28
  • 18798

Android中AsyncTask的使用与源码分析

Android中AsyncTask的使用与源码分析
  • xilove102
  • xilove102
  • 2016年07月28日 11:08
  • 596
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:AsyncTask源码浅析
举报原因:
原因补充:

(最多只允许输入30个字)