AsyncTask知识梳理

上一篇我们讲解了Handler的相关知识,这篇文章就在来对AsyncTask进行讲解。
那么,什么是AsyncTask呢?AsyncTask是一种轻量级的异步线程类,它可以在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程并在主线程更新UI。简单来说AsyncTask也就是对Handler和线程池的封装。

我们先来看下AsyncTask的一个简单例子:

1        AsyncTask asyncTask = new AsyncTask() {
2            @Override
3            protected String doInBackground(String... params) {
4                return params[0];
5            }

6            @Override
7            protected void onProgressUpdate(Integer... values) {
8                progressBar.setProgress(values[0]*100/1000);
9            }

10            @Override
11            protected void onPostExecute(String s) {
12                Log.e("LHC", "result:"+ s); 
13            }

14            @Override
15            protected void onPreExecute() {
16                //TODO 
17            }
18        };

19        asyncTask.execute("AsyncTask 测试");
  • 1行:生成了一个AsyncTask类对象,而AsyncTask是一个抽象类,具体定义为AsyncTask,其中参数Params为在执行任务时,发送给任务的参数类型,也就是方法doInBackground的参数类型;参数Progress为后台执行期间的进度类型,也就是方法onProgressUpdate的参数类型;参数Result为后台执行的结果类型,也就是方法onPostExecute的参数类型。
  • 2~5行:doInBackground(Params... params)方法,在方法中定义后台线程要执行的任务,参数在执行任务也就是调用execute(Params... params)时传入;在方法中可以执行publishProgress(Progress... values)方法,用来更新UI。
  • 6~9行:onProgressUpdate(Progress... values)方法,在UI中用来更新任务进度,由publishProgress(Progress... values)方法内部进行调用。
  • 10~13行:onPostExecute(Result result)方法,在UI线程中用于保存或者显示结果。参数resultdoInBackground执行后的返回结果。
  • 14~17行:onPreExecute()方法,用于做一些准备工作。在doInBackground方法之前调用。
  • 19行:execute(Params... params)方法,执行任务,params就是要传入的参数值。

这样就完成了AsyncTask的简单使用,下面我们就看看源码内部的实现。看第1行代码new AsyncTask()中的代码实现:

    /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     */
    public AsyncTask() {
        this((Looper) null);
    }

    /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     *
     * @hide
     */
    public AsyncTask(@Nullable Looper callbackLooper) {
1       mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);

2       mWorker = new WorkerRunnable() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                Result result = null;
                try {
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    //noinspection unchecked
3                   result = doInBackground(mParams);
                    Binder.flushPendingCommands();
                } catch (Throwable tr) {
                    mCancelled.set(true);
                    throw tr;
                } finally {
4                   postResult(result);
                }
                return result;
            }
        };

5       mFuture = new FutureTask(mWorker) {
            @Override
            protected void done() {
                try {
6                   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) {
7                    postResultIfNotInvoked(null);
                }
            }
        };
    }

需要注意的是,代码中的两个构造方法都需要在主线程中运行,看两个方法的注释。代码最终调用到了带参数的AsyncTask(@Nullable Looper callbackLooper)构造函方法,具体分析如下:

  • 1行:根据传入的callbackLooper参数是否为空或者是否为Looper.getMainLooper()也就是主线程的Looper值,来生成一个Handler对象;当为空或者值相等时,调用了getMainHandler()方法;当不为空或者值不相等时,调用了new Handler(callbackLooper)
    getMainHandler()方法,具体代码为:
    private static Handler getMainHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new InternalHandler(Looper.getMainLooper());
            }
            return sHandler;
        }
    }

    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类对象,传入的是主线程的Looper值。在看InternalHandler类中,在handleMessage中处理了得到的消息。这里的消息有两种类型MESSAGE_POST_RESULTMESSAGE_POST_PROGRESS
MESSAGE_POST_RESULT时,执行了finish方法,代码为:

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

在if语句中判断isCancelled的值,也就是任务是否取消来决定执行取消任务还是调用返回结果的方法onPostExecute。最后将任务状态设置为FINISHED
MESSAGE_POST_PROGRESS时,执行了onProgressUpdate方法,用来更新任务执行的进度。

  • 2,3,4行:生成了一个WorkerRunnable对象mWorker,而这个类是个抽象类并且实现了Callable接口,因此mWorker也就是一个线程类。在call()方法中设置了线程的优先级,并调用了doInBackground(mParams)方法用来执行后台任务;如果出现异常就调用postResult(result)方法。
    postResult(result)方法的具体代码如下:
    private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult(this, result));
        message.sendToTarget();
        return result;
    }

在这个方法中发送了一条消息类型为MESSAGE_POST_RESULT的消息。

  • 5,6,7行:将上面得到的mWorker作为参数生成了一个FutureTask对象mFuture,而FutureTask类实现了RunnableFuture接口,而RunnableFuture又实现了Runnable, Future接口,因此mFuture也可以看做是一个线程。接下来在FutureTask下的done方法中调用了postResultIfNotInvoked(get())方法。
    postResultIfNotInvoked(get())方法的具体代码如下:
    private void postResultIfNotInvoked(Result result) {
        final boolean wasTaskInvoked = mTaskInvoked.get();
        if (!wasTaskInvoked) {
            postResult(result);
        }
    }

这个方法用来判定是否已经执行过postResult(result)方法。
看第19行代码asyncTask.execute("AsyncTask 测试")中的代码实现:

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

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

需要注意的是,这两个执行方法也是需要是主线程中执行的。执行代码最终进入了executeOnExecutor执行方法。此方法中现根据任务的mStatus状态值,判定任务是否正在执行或者已经执行过了,如果正在执行或者已经执行过了,就不能在调用执行方法进行执行了,也就是一个AsyncTask任务只能执行一次;如果没有执行过,将任务状态改为正在执行,然后调用onPreExecute()做执行任务前的准备工作,在将传入的参数赋值给mWorker中的mParams变量,最后线程池exec执行线程mFuture。这里的exec也就是sDefaultExecutor,定义如下:

    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

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

从这里的代码可以看出,SerialExecutor继承与Executor,重写了执行方法execute,并且给这个方法加了同步锁,而sDefaultExecutor是SerialExecutor的对象,所以这个线程池也就是一个串行的线程池,任务一个执行完成后另一个才能执行。方法execute中,将生成的新任务加入到mTasks任务队列尾部,而在新任务中执行了r.run()方法,此方法为调用exec.execute(mFuture)中传入的mFuture中的run方法,而在这个run方法中执行了mWorker中的call()方法,这样后台线程也就开始执行了。执行完r.run()之后,又执行了scheduleNext()方法。在这个方法中,通过调用mTasks.poll()方法,删除并获取队列中第一个元素的值,将其赋值mActive,如果值不为空,使用线程池THREAD_POOL_EXECUTOR执行线程mActive;为空则退出。

这样AsyncTask的一整套流程就走完了,但是需要注意的是execute方法默认是串行执行的,也就是一个任务执行完了,另一个才能执行;如果你不想等待一个任务执行完成就去执行另一个任务,该怎么办呢?这时就需要调用executeOnExecutor方法,并传入系统为我们准备好的并行执行的线程池AsyncTask.THREAD_POOL_EXECUTOR,这样就完成了任务的并行执行。简单的例子如下:

        /**
         * 调用“execute”在程序还未执行完时,退出;那么子线程会在后台继续执行,直到执行完成;
         * 当子线程在没有执行完成时,在此调用“execute”方法,此时新建立的子线程并不会执行,只有等上一个子线程执行完成后才能执行。
         * 因为这个方法中的线程池“AsyncTask.SERIAL_EXECUTOR”是串行执行的。
         */
        task.execute("Use Test of AsyncTask.", "1000");
        /**
         * 调用“executeOnExecutor”在程序还未执行完时,退出;子线程在后台继续运行;
         * 当子线程在没有执行完成时,在此调用“executeOnExecutor”方法,新建立的子线程立刻执行。
         * 因为这个方法中的线程池“AsyncTask.THREAD_POOL_EXECUTOR”是并行执行的
         */
        task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "Use Test of AsyncTask.", "1000");

在上面的代码中,也注释了使用并行的一种情况。

你可能感兴趣的:(AsyncTask知识梳理)