AsyncTask 介绍

AsyncTask 是一种轻量级的异步任务类,他可以在线程池中执行后台任务,但是 AsyncTask 并不适合执行特别耗时的后台任务,对于特别耗时的任务,建议使用线程池。

查看 AsyncTask 源码可知道其不适合执行特别耗时的任务:

AsyncTask is designed to be a helper class around {@link Thread} and {@link Handler}
* and does not constitute a generic threading framework. AsyncTasks should ideally be
* used for short operations (a few seconds at the most.) If you need to keep threads
* running for long periods of time, it is highly recommended you use the various APIs
* provided by the java.util.concurrent package such as {@link Executor},
* {@link ThreadPoolExecutor} and {@link FutureTask}.


AsyncTask 是一个抽象的泛型类,他提供了 Params,Progress,Result 这三个泛型参数,Params 表示参数的类型,Progress 表示后台任务执行的进度,Result 表示后台任务的返回结果的类型,如果 AsyncTask 不需要床底参数,三个参数可直接用 Void 表示。

AsyncTask 提供了几个核心方法,它们的含义如下:

  • onPreExecute()
    主线程执行,在异步任务开始之前执行,在该方法中可以做一些准备工作

  • doInBackground(Params…params)
    线程池中执行,此方法用于执行异步任务,params 参数表示异步任务的输入参数,在该方法中可以调用publishProgress(Integer...values);来更新任务进度,而该方法会调用onProgressUpdate()方法。

  • onProgressUpdate(Progress…values)
    主线程中执行, 当后台任务的执行进度发生改变时会调用该方法。

  • onCancelled(Long aLong)
    主线程中执行,当任务被取消时,onPostExecute方法不会被调用。取消任务的方法是:
if (task.getStatus() == AsyncTask.Status.RUNNING){    task.cancel(true) ;}
  • onPostExecute(Result result)
    主线程中执行,在异步任务执行完成之后,该方法会被调用,其中result参数是后台任务的返回值,即doInBackground()的返回值。

AsyncTask 使用时候的一些限制

AsyncTask 在具体的使用过程中会有一些条件限制,主要有以下几点:

  • AsyncTask 的类必须在主线程中加载,在 android4.1 以上已经被系统自动完成。

因为源码中Handler对象是一个静态的成员对象,而静态成员对象在加载类时会自动进行初始化。 又因为Handler对象是在主线程中创建,所以AsyncTask类也是在主线程中加载。

  • AsyncTask 的对象必须在主线程中创建

因为 AsyncTask是封装了ThreadHandler,为了能够将执行环境切换到主线程这就要求源码中的Handler对象必须在主线程中创建。

  • execute 方法必须在 UI 线程中加载
    因为exrcute()调用的executeOnExecutor()中执行了的onPreExecute();方法,该方法是在UI线程中执行,所以execute 方法必须在 UI 线程中加载

  • 不要在程序中直接调用 onPreExecute()、onPostExecute、doInBackgroung()和 onProgressUpdate()

  • 一个 AsyncTask 对象只能执行一次,即只能调用一次 execute 方法,否则会报运行时异常。源码中写道:

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)");    }}
  • 在 Android 1.6 之前,AsyncTask 是串行执行任务,Android 1.6 之后开始采用线程池来处理并行任务,但是从 Android 3.0 开始,为了避免 AsyncTask 所带来的并发错误, AsyncTask 有采用一个线程来串行执行任务。尽管如此,在 Android 3.0 即后续的版本中,我们仍然可以通过 AsyncTask 的 executeOnExecutor 方法来并行的执行任务。

AsyncTask 工作原理分析

找到入口 execute() 方法一路跟踪。

进入 execute() 该方法又调用 executeOnExecutor() 方法。

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

在 executeOnExecutor 方法中发现先调用了onPreExcute()方法,然后开始执行线程池中的任务。

@MainThreadpublic final AsyncTask 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()发现它是Executor接口中的一个方法,那么就找找exec是什么?

/** @hide */public static void setDefaultExecutor(Executor exec) {    sDefaultExecutor = exec;}

sDefaultExecutor被赋值为:

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

SERIAL_EXECUTORSerialExecutor的实例:

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

SerialExecutor的实现如下:

private static class SerialExecutor implements Executor {    final ArrayDeque mTasks = new ArrayDeque();    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默认是串行执行的,因为在mTask任务队列中没有正在活动的 AsyncTask 任务才会执行SerialExecutor 的 scheduleNext 方法去执行下一个任务。

那么它是如何在得到任务进度和执行的结果呢?
在构造函数中又这么一段:

mWorker = new WorkerRunnable() {    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;    }};

可以看到doInBackgroung返回的值给了result,然后通过postResult(result)发送出去,postResult()代码如下:

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

可以看到是通过消息发送出去了,那我们找到Handler 中处理消息的方法 handleMessage看看收到消息后是如何处理的,找到handleMessage:

private static class InternalHandler extends Handler {    public InternalHandler(Looper looper) {        super(looper);    }    @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;        }    }}

InternalHandler实例的创建如下:

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

可以看到sHandler是一个静态的Handler对象,为了能够将执行环境切换到主线程,这就要求sHandler对象必须在主线程中创建,又因为静态成员会在加载类的时候进行初始化,所以这也就变相要求AsyncTask的类必须在主线程中加载,否则同一个进程中的AsyncTask都将无法正常工作。

可以看到在接收到MESSAGE_POST_RESULT消息后执行了result.mTask.finish(result.mData[0]),也就是调用了AsyncTask 自己的 finish(),方法如下:

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

finish方法中判断如果AsyncTask任务被取消,直接调用onCancelled(result);取消任务,否则调用onPostExecute(result) ;去执行任务。

更多相关文章

  1. Android(安卓)中Service组件
  2. 黑马程序员12——android之事件传播机制
  3. android Debug调试
  4. 二种方法实现 Android(安卓)TabWidget
  5. Android的onMeasure和onLayout And MeasureSpec揭秘
  6. Android中实现震动的方法
  7. Android学习笔记两篇关于线程更新UI的方法的文章
  8. Android(安卓)L 新特性
  9. Android异步任务简单使用

随机推荐

  1. android 模拟器获取root权限
  2. Android input 输入系统学习
  3. Running Android with low RAM
  4. [Android交互]Android与Unity的交互
  5. android byte[]与图片的转换
  6. Android ImageView图片自适应
  7. Android和Java本地数据库新选择
  8. Android 内存
  9. S5PV210 ANDROID 为摄像头增加闪光灯
  10. 系出名门Android(6) - 控件(View)