引言

在Android中实现异步任务,我们可以直接使用Handler+Thread的方式。这种方式需要为每一个任务创建一个新的线程,任务完成后通过Handler实例向UI线程发送消息,完成界面的更新,这种方式对于整个过程的控制比较精细,但也是有缺点的,例如代码相对臃肿,在多个任务同时执行时,不易对线程进行精确的控制。

为了简化操作,Android SDK为我们提供了工具类android.os.AsyncTask,它使创建异步任务变得更加简单,不再需要编写任务线程和Handler实例即可完成相同的工作。

AsyncTask的使用

定义

来看AsyncTask的声明:

public abstract class AsyncTask< Params, Progress, Result > {    ……}

Params, Progress, Result三种泛型分别代表“启动任务执行的输入参数”、“后台任务执行的进度”、“后台计算结果的类型”。在特定场合下,并不是所有类型都被使用,如果没有被使用,可以用Java.lang.Void类型代替。

方法

AsyncTask的执行一般涉及到以下几个方法:

1.execute(Params… params):执行一个异步任务,需要我们在代码中调用此方法,触发异步任务的执行。

2.onPreExecute():execute(Params… params)被调用后立即执行,一般用来在执行后台任务前对UI做一些标记。

3.doInBackground(Params… params):onPreExecute()完成后立即执行,用于执行较为费时的操作,此方法将接收输入参数和返回计算结果。在执行过程中可以调用publishProgress(Progress… values)来更新进度信息。

4.onProgressUpdate(Progress… values):在调用publishProgress(Progress… values)时,此方法被执行,直接将进度信息更新到UI组件上。

5.onPostExecute(Result result):当后台操作结束时,此方法将会被调用,计算结果将做为参数传递到此方法中,直接将结果显示到UI组件上。

使用注意点

1.异步任务的实例必须在UI线程中创建。
2.execute(Params… params)方法必须在UI线程中调用。
3.不要手动调用onPreExecute(),doInBackground(Params… params),onProgressUpdate(Progress… values),onPostExecute(Result result)这几个方法。
4.不能在doInBackground(Params… params)中更改UI组件的信息。
5.一个任务实例只能执行一次,如果执行第二次将会抛出异常。

AsyncTask的源码分析

以下源码基于API25。

首先来看到一段代码:

    private volatile Status mStatus = Status.PENDING;    /**     * Indicates the current status of the task. Each status will be set only once     * during the lifetime of a task.     */    public enum Status {        /**         * Indicates that the task has not been executed yet.         */        PENDING,        /**         * Indicates that the task is running.         */        RUNNING,        /**         * Indicates that {@link AsyncTask#onPostExecute} has finished.         */        FINISHED,    }

Status枚举类用来表示AsyncTask的状态,有还未开始,正在进行和已结束三种状态。
mStatus作为AsyncTask的成员变量,记录了AsyncTask的状态。

然后再看AsyncTask启动方法execute(Params… params)

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

这里其实把任务交给了executeOnExecutor()

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

以上代码中,我们发现mStatus的状态被修改为正在进行

然后调用了onPreExecute()onPreExecute()默认是空实现,如果我们重写了它,那就执行我们重写的内容。
onPreExecute()的作用,之前说过,就是在异步任务开启前,做一些UI的准备工作。

接下来介绍出现的三个很重要的变量,mWorkermFuturesDefaultExecutor(就是这里的exec)。

sDefaultExecutor

    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;    public static final Executor SERIAL_EXECUTOR = new 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);            }        }    }

仔细看以上代码,sDefaultExecutor是一个串行的线程池。为什么说它是串行的线程池呢?

他内部维护了一个队列mTasks ,当execute被执行的时候,只是通过mTasksoffer方法把传递进来的Runnable加入队列,而且它是执行完一个Runnable再去调用scheduleNext()执行下一个Runnable

最后真正去执行操作的其实是THREAD_POOL_EXECUTOR

    public static final Executor THREAD_POOL_EXECUTOR            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

它才是一个真正的线程池。

mWorker

        mWorker = new WorkerRunnable() {            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);            }        };        private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {            Params[] mParams;        }

mWorker实际上是AsyncTask的一个的抽象内部类WorkerRunnable的实例对象,WorkerRunnable其实就是一个Callable

mFuture

        mFuture = new FutureTask(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);                }            }        };        public class FutureTask<V> implements RunnableFuture<V> {            ……        }        public interface RunnableFuture<V> extends Runnable, Future<V> {        /**         * Sets this Future to the result of its computation         * unless it has been cancelled.         */            void run();        }}

mFutureFutureTask的实例,FutureTask是一个接口,它继承了RunnableFuture
如果对它们之间的关系不了解,可以先跳到本文最后一节

然后继续看mWorkermFuture实例在AsyncTask中的体现,他们在AsyncTask的构造函数中被初始化:

    public AsyncTask() {        mWorker = new WorkerRunnable() {            public Result call() throws Exception {                //call方法被调用后,将设置优先级为后台级别,然后调用AsyncTask的doInBackground方法                  mTaskInvoked.set(true);                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);                //noinspection unchecked                Result result = doInBackground(mParams);                Binder.flushPendingCommands();                return postResult(result);            }        };        //在mFuture实例中,将会调用mWorker做后台任务,完成后会调用done方法          mFuture = new FutureTask(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);                }            }        };    }

其中mWorkercall()中调用了doInBackground(),我们可以在doInBackground()进行后台耗时操作。

mFuturedone()中会调用postResultIfNotInvoked(),然后又会去调用postResult()

    private void postResultIfNotInvoked(Result result) {        final boolean wasTaskInvoked = mTaskInvoked.get();        if (!wasTaskInvoked) {            postResult(result);        }    }    private Result postResult(Result result) {        @SuppressWarnings("unchecked")        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,                new AsyncTaskResult(this, result));        message.sendToTarget();        return result;    }

这里好像看到了Handler发送消息,我们看到getHandler()

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

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

InternalHandler继承自Handler

如果sHandler接收到的消息是MESSAGE_POST_PROGRESS,那就去调用onProgressUpdate(),它也是默认空实现的,我们在这里可以去实时刷新UI。

如果接收到的消息是MESSAGE_POST_RESULT,那就去调用AsyncTaskfinish()

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

如果是被取消的,就去执行onCancelled()
如果不是就去执行onPostExecute()onPostExecute()默认也是空实现,我们在这里可以对UI进行最后的操作,比方说取消加载进度条,提示加载完毕。

最后将mStatus置为已结束。

经过上面的介绍,相信大家都已经认识到AsyncTask的本质了,它是对Thread+Handler的良好封装,减少了开发者处理问题的复杂度,提高了开发效率。

Runnable、Callable、Future、FutureTask的关系

刚才讲到了mWorkermFuture,我第一次看到的时候内心的疑惑还是很多的。所以在这里插入进来,介绍一下它们。

Runnable:

public interface Runnable {    /**     * Starts executing the active part of the class' code. This method is     * called when a thread is started that has been created with a class which     * implements {@code Runnable}.     */    public void run();}

Runnable应该是我们最熟悉的接口,它只有一个run()函数,用于将耗时操作写在其中,该函数没有返回值。然后使用某个线程去执行该runnable即可实现多线程,Thread类在调用start()函数后就是执行的是Runnable的run()函数。

Callable:

public interface Callable {    /**     * Computes a result, or throws an exception if unable to do so.     *     * @return computed result     * @throws Exception if unable to compute a result     */    V call() throws Exception;}

CallableRunnable的功能大致相似,Callable中有一个call()函数,但是call()函数有返回值,而Runnable的run()函数不能将结果返回给客户程序。可以看到,它是一个泛型接口,call()函数返回的类型就是客户程序传递进来的V类型。

Future:

public interface Future {    boolean cancel(boolean mayInterruptIfRunning);    boolean isCancelled();    boolean isDone();    V get() throws InterruptedException, ExecutionException;    V get(long timeout, TimeUnit unit)        throws InterruptedException, ExecutionException, TimeoutException;}

以上代码省略了注释。

Future就是RunnableCallable的调度容器,Future能够对具体的Runnable或者Callable进行取消任务查询任务是否完成获取结果设置结果这几个操作。get方法会阻塞线程,直到任务返回结果。

FutureTask:

        public class FutureTask<V> implements RunnableFuture<V> {            ……        }

FutureTask则是一个RunnableFuture

        public interface RunnableFuture<V> extends Runnable, Future<V> {        /**         * Sets this Future to the result of its computation         * unless it has been cancelled.         */            void run();        }

另外FutureTask还可以包装RunnableCallable, 由构造函数注入依赖:

public FutureTask(Callable callable) {      if (callable == null)          throw new NullPointerException();      this.callable = callable;      this.state = NEW;       // ensure visibility of callable  }  public FutureTask(Runnable runnable, V result) {      this.callable = Executors.callable(runnable, result);      this.state = NEW;       // ensure visibility of callable  } 

可以看到,注入的Runnable会被Executors.callable()转换为Callable类型,即FutureTask最终都是执行Callable类型的任务。Executors.callable()的实现如下 :

    public static  Callable callable(Runnable task, T result) {        if (task == null)            throw new NullPointerException();        return new RunnableAdapter(task, result);    }

RunnableAdapter适配器:

    static final class RunnableAdapter<T> implements Callable<T> {        final Runnable task;        final T result;        RunnableAdapter(Runnable task, T result) {            this.task = task;            this.result = result;        }        public T call() {            task.run();            return result;        }    }

FutureTask实现了两个接口,RunnableFuture,所以它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值,那么这个组合的使用有什么好处呢?假设有一个很费时逻辑需要计算并且返回这个值,同时这个值不是马上需要,那么就可以使用这个组合,用另一个线程去计算返回值,而当前线程在使用这个返回值之前可以做其它的操作,等到需要这个返回值时,再通过Future得到。

参考:
1.Java中的Runnable、Callable、Future、FutureTask的区别与示例
2.详解Android中AsyncTask的使用

更多相关文章

  1. Android(安卓)消息机制——你真的了解Handler?
  2. Android(安卓)双缓冲技术
  3. android graphics下的Paint类,Path类,Canvas类
  4. Android消息机制及HandlerThread、Handler内存泄漏问题
  5. 换一种方式理解 Android协程
  6. android之Handler整理
  7. Android事件传递机制(更加深入的了解事件的触发过程)
  8. Handler原理
  9. android HTTP 通信, XML 解析, 通过 Hander 实现异步消息处理 (1)

随机推荐

  1. Android流量统计代码
  2. android 音视频录制
  3. i.MX Android(安卓)R10.3 User Guide Upd
  4. Android(安卓)Res xml
  5. android 自定义表盘控件
  6. Android(安卓)高德地图驾车路线规划
  7. Android(安卓)广播(Android(安卓)10)
  8. Android(安卓)SMS(一) —— 读取短信
  9. android 利用service来播放音乐
  10. android判断网络状态