AsyncTask的使用及源码分析

引言

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

以上代码中,我们发现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<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);
            }
        }
    }

仔细看以上代码,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<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);
            }
        };

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

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

mFuture

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

        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<Params, Result>() {
            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<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);
                }
            }
        };
    }

其中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<Result>(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<V> {
    /**
     * 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<V> {

    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<V> 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 <T> Callable<T> callable(Runnable task, T result) {
        if (task == null)
            throw new NullPointerException();
        return new RunnableAdapter<T>(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的使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值