AsyncTask,是Android提供的一个用于执行异步任务的类,它可以通过线程池执行后台任务,并实时更新后台任务的执行进度,以及在任务执行完成可以将任务的执行结果返回给UI线程以更新UI。在我看来,AsyncTask主要是对Handler和Callable使用的一个封装,如果对这两个知识点不太清楚可以看下我之前的Blog:Android Handler消息机制源码分析 以及 java Callable与Future线程详解
通过查看AsyncTask的源码可知,AsyncTask是一个抽象的泛型类,该类定义了三个泛型参数:
public abstract class AsyncTask<Params, PRogress, Result> { // 代码略}Params:表示参数类型Progress:实时更新后台任务的进度的类型Result:返回结果的类型这里注意,如果不需要确定泛型参数的类型,我们只需要传递Void即可。
在AsyncTask使用中,我们一般需要复写4个方法,如下代码所示:
public class DownloadTask extends AsyncTask<String, Integer, String>{ /** * 1、在异步任务执行之前调用,主要做一些初始化的工作 */ @Override protected void onPreExecute() { // TODO Auto-generated method stub super.onPreExecute(); } /** * 2、该方法会在线程池中运行,异步任务主要在此执行。 */ @Override protected String doInBackground(String... params) { return null; } /** * 3、在异步任务执行期间实时更新进度,此方法主要是被publishProgress方法 */ @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); } /** * 4、该方法在主线程中调用,异步任务执行完成,获取异步任务的执行结果,一般在该方法中对执行结果进行处理 */ @Override protected void onPostExecute(String result) { super.onPostExecute(result); }}想通过上面定义的DownloadTask完成一个任务也非常简单,只要调用AsyncTask的execute()方法即可,如下所示:
new DownloadTask().execute(url);AsyncTask方法注意事项:
AsyncTask必须在主线程中创建,这主要是因为AsyncTask内部使用了Handler机制,该Handler主要作用是完成子线程和主线程的通信。execute方法必须在UI线程中调用。一个AsyncTask实例只能调用一次execute方法,否则会出现运行时异常。execute方法作为AsyncTask执行异步任务的入口,我们首先来看看这个方法的内部实现。
public final AsyncTask<Params, Progress, Result> execute(Params... params) { // sDefaultExecutor,是一个线程池 return executeOnExecutor(sDefaultExecutor, params);}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; // 1、首先执行onPreExecute onPreExecute(); // 2、mWorker是一个callable对象 mWorker.mParams = params; // 3、mFuture是一个FutureTask对象,该对象封装了mWorker对象,通过exec线程值执行异步任务 exec.execute(mFuture); return this;}在execute方法中,使用了sDefaultExecutor,这是一个串行的线程池,在AsyncTask中主要用于任务的排列。同时,在AsyncTask中还定义了一个线程池THREAD_POOL_EXECUTOR,该线程池真正用于执行线程的。代码如下
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;private static class SerialExecutor implements Executor { // ArrayDeque,是一个双端队列,没有容量限制 // 这里主要用于存储异步任务 final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); Runnable mActive; public synchronized void execute(final Runnable r) { // offer方法:将指定元素添加到双端队列的末尾 mTasks.offer(new Runnable() { // 这里通过创建一个新的Runnable对象对原有参数的Runnable参数进行封装 public void run() { try { r.run(); } finally { /** * 因为sDefaultExecutor是一个静态类,这就导致相同进程中会使用这同一个线程池 * 每当一个任务完成后调用scheduleNext方法保证,线程池队列中任务能够持续的执行,知道任务队列中没有任务为止 */ scheduleNext(); } } }); if (mActive == null) { scheduleNext(); } } // 这是执行任务的核心方法 protected synchronized void scheduleNext() { // 首先从任务队列mTasks中通过poll方法获取队列第一个元素 if ((mActive = mTasks.poll()) != null) { // THREAD_POOL_EXECUTOR也是一个线程池,这个是真正用于执行任务。 THREAD_POOL_EXECUTOR.execute(mActive); } } public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);}在上述的过程中,就完成了通过线程池执行异步任务的过程,现在我们来看看异步任务执行的具体细节,这里就要通过分析在AsyncTask中Callable和FutureTask是如何被使用的。
首先,我们看看AsyncTask的构造方法,如下代码所示。
public AsyncTask() { // mWorker就是Callable的具体实现 mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); // 通过doInBackground方法获取返回值,然后通过postResult方法使用handler方法发送一个消息,将异步任务的结果发送给UI线程 return postResult(doInBackground(mParams)); } }; // FutureTask的实例,这个会被线程池执行 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); } } };}private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> { Params[] mParams;}// 异步任务的结果发送给UI线程private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); return result;}在上面postResult方法中使用了sHandler用于发送消息,我们来看看Handler在AsyncTask中的使用。
/** * sHandler是一个静态对象,为了能够使Handle人能够将消息发送给主线程,这就要求sHandler必须在主线程中被创建, * 由于静态变量会在类加载时初始化,这就要求AsyncTask必须在主线程中初始化。 * */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: // 当异步任务执行完成或者任务被取消时,会执行finish方法 result.mTask.finish(result.mData[0]); break; case MESSAGE_POST_PROGRESS: result.mTask.onProgressUpdate(result.mData); break; } }}private void finish(Result result) { if (isCancelled()) { // 当任务取消时,执行该方法 onCancelled(result); } else { // 当任务执行完成执行onPostExecute,并对任务结果进行处理 onPostExecute(result); } mStatus = Status.FINISHED;}这样,整个AsyncTask的执行过程及原理大致就是如此了。
新闻热点
疑难解答