Android查缺补漏(线程篇)-- AsyncTask的使用及原理详细分析

书史足自悦,安用勤与劬。这篇文章主要讲述Android查缺补漏(线程篇)-- AsyncTask的使用及原理详细分析相关的知识,希望能为你提供帮助。
本文作者:CodingBlock  文章链接:http://www.cnblogs.com/codingblock/p/8515304.html
一、AsyncTask的使用
AsyncTask是一种轻量级的异步任务类,可以很方便的在线程池中执行异步任务,并且将进度和结果传递给主线程。其底层由Thread+handler实现。
AsyncTask是一个抽象的泛型类,其类的声明如下:

public abstract class AsyncTask< Params, Progress, Result>

其中三个泛型参数代表的意义如下:
  • Parmas:参数类型
  • Progress:异步任务的执行进度类型
  • Result:异步任务执行完毕后返回结果的类型
在使用AsyncTask执行异步任务需要创建一个类,让这个类继承AsyncTask,并实现相关方法,具体形式如下,在下面代码中实现了几个重要的方法,每个方法代表的意义可以见注释:
/** * Created by liuwei on 18/2/28. */ public class MyAsyncTask extends AsyncTask< String, Integer, String> {/** * 在异步任务执行之前调用 * 执行在主线程中 */ @Override protected void onPreExecute() { super.onPreExecute(); }/** * 执行异步任务 * 执行在线程池中 * @param params * @return */ @Override protected String doInBackground(String... params) { return null; }/** * 当异步任务被取消时执行此方法,此时将不会再调用onPostExecute方法 */ @Override protected void onCancelled() { super.onCancelled(); }/** * 当异步任务执行进度改变时执行此方法 * 执行在主线程中 * @param values */ @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); }/** * 当异步任务执行完成后执行此方法 * 执行在主线程中 * @param s */ @Override protected void onPostExecute(String s) { super.onPostExecute(s); } }

要注意的是,需要在doInBackground方法中调用publishProgress()发送任务执行进度,onProgressUpdate才能被回调。
执行AsyncTask是需要在主线程中调用:
new MyAsyncTask().execute();

在使用AsyncTask时有一些限制我们要注意:
  • AsyncTask类必须在主线程中加载。这是因为在AsyncTask中存在这个一个静态类型的Handler对象成员,在AsyncTask被加载时,该静态类型的Handler对象就会被初始化,所以这就要求了首次访问AsyncTask要发送在主线程中。这一点在android 4.1及以上版本中已经被系统自动完成。
  • AsyncTask的对象必须在主线程中创建。
  • AsyncTask的execute必须在主线程中调用。
  • 不能直接调用onPreExecute()、doInBackground()、onProgressUpdate()、onPostExecute()方法。
  • 一个AsyncTask对象只能调用一次execute,即每个对象只能被执行一次,否则会出异常。
1、使用AsyncTask执行异步任务的小例子接下类使用AsyncTask,借助循环模拟一个耗时任务的小例子,还是用上面的MyAsyncTask类,并在其相关方法上面添加一些辅助代码,详细代码如下:
public class MyAsyncTask extends AsyncTask< String, Integer, String> {private final static String TAG = MyAsyncTask.class.getSimpleName(); private int taskSize = 10; /** * 在异步任务执行之前调用 * 执行在主线程中 */ @Override protected void onPreExecute() { super.onPreExecute(); Log.i(TAG, "onPreExecute: "); }/** * 执行异步任务 * 执行在线程池中 * @param params * @return */ @Override protected String doInBackground(String... params) { Log.i(TAG, "doInBackground: "); int i; for (i = 0; i < taskSize; i++) { SystemClock.sleep(1000); int progress = (int)((i / (float)taskSize) * 100); publishProgress(progress); if (isCancelled()) { break; } } return "执行结果:" + (i / (float)taskSize) * 100 + "%"; }/** * 当异步任务被取消时执行此方法,此时将不会再调用onPostExecute方法 */ @Override protected void onCancelled() { super.onCancelled(); Log.i(TAG, "onCancelled: "); }@Override protected void onCancelled(String s) { super.onCancelled(s); Log.i(TAG, "onCancelled: result=" + s); }/** * 当异步任务执行进度改变时执行此方法 * 执行在主线程中 * @param values */ @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); Log.i(TAG, "onProgressUpdate: 执行进度:" + values[0] + "%"); }/** * 当异步任务执行完成后执行此方法 * 执行在主线程中 * @param s */ @Override protected void onPostExecute(String s) { super.onPostExecute(s); Log.i(TAG, "onPostExecute: result=" + s); } }

在Activity中调用new MyAsyncTask().execute(); 执行Log如下:
.../cn.codingblock.thread I/MyAsyncTask: onPreExecute: .../cn.codingblock.thread I/MyAsyncTask: doInBackground: .../cn.codingblock.thread I/MyAsyncTask: onProgressUpdate: 执行进度:0% .../cn.codingblock.thread I/MyAsyncTask: onProgressUpdate: 执行进度:10% .../cn.codingblock.thread I/MyAsyncTask: onProgressUpdate: 执行进度:20% .../cn.codingblock.thread I/MyAsyncTask: onProgressUpdate: 执行进度:30% .../cn.codingblock.thread I/MyAsyncTask: onProgressUpdate: 执行进度:40% .../cn.codingblock.thread I/MyAsyncTask: onProgressUpdate: 执行进度:50% .../cn.codingblock.thread I/MyAsyncTask: onProgressUpdate: 执行进度:60% .../cn.codingblock.thread I/MyAsyncTask: onProgressUpdate: 执行进度:70% .../cn.codingblock.thread I/MyAsyncTask: onProgressUpdate: 执行进度:80% .../cn.codingblock.thread I/MyAsyncTask: onProgressUpdate: 执行进度:90% .../cn.codingblock.thread I/MyAsyncTask: onPostExecute: result=执行结果:100.0%

2、多个AsyncTask对象在执行异步任务时,默认是串行执行的,也可以通过executeOnExecutor让其并发执行。
  • 在Android 1.6之前,AsyncTask处理任务时是采用串行方式,Android 1.6时,AsyncTask处理任务时是在线程池中并行处理任务。但在Android 3.0开始,AsyncTask又开始采用串行方式处理任务。
我们稍加改造一下上面的示例,在构造方法中传入一个taskId,然后在关键log中输出这个taskId,以便于区分:
private int taskId; public MyAsyncTask(int taskId) { this.taskId = taskId; }/** * 在异步任务执行之前调用 * 执行在主线程中 */ @Override protected void onPreExecute() { super.onPreExecute(); Log.i(TAG, "taskId= " + taskId + ": onPreExecute: "); }// 其他方法类比onPreExecute方法中的log增加taskId,就不贴出了

在Activity中初始化两个AsyncTask对象,并调用excute执行任务:
public class AsyncTaskActivity extends AppCompatActivity {@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_async_task); MyAsyncTask task1 = new MyAsyncTask(1); MyAsyncTask task2 = new MyAsyncTask(2); task1.execute(); task2.execute(); } }

log如下:
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onPreExecute: .../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onPreExecute: .../cn.codingblock.thread I/MyAsyncTask: taskId= 1: doInBackground: .../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:0% .../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:10% .../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:20% .../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:30% .../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:40% .../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:50% .../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:60% .../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:70% .../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:80% .../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:90% .../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onPostExecute: result=taskId= 1: 执行结果:100.0% .../cn.codingblock.thread I/MyAsyncTask: taskId= 2: doInBackground: .../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:0% .../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:10% .../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:20% .../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:30% .../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:40% .../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:50% .../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:60% .../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:70% .../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:80% .../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:90% .../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onPostExecute: result=taskId= 2: 执行结果:100.0%

可以看到两个任务是串行执行的。
  • 使用executeOnExecutor方法
【Android查缺补漏(线程篇)-- AsyncTask的使用及原理详细分析】AsyncTask
executorOnExecutor方法有两个参数,第一个是Executor,第二个是任务参数。
第一个参数有两种类型:
  • AsyncTask.SERIAL_EXECUTOR : 表示串行执行
  • AsyncTask.THREAD_POOL_EXECUTOR :表示并发执行
在执行task2时调用executeOnExecutor,观察执行结果:
public class AsyncTaskActivity extends AppCompatActivity {@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_async_task); MyAsyncTask task1 = new MyAsyncTask(1); MyAsyncTask task2 = new MyAsyncTask(2); task1.execute(); task2.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } }

log如下:
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onPreExecute: .../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onPreExecute: .../cn.codingblock.thread I/MyAsyncTask: taskId= 1: doInBackground: .../cn.codingblock.thread I/MyAsyncTask: taskId= 2: doInBackground: .../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:0% .../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:0% .../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:10% .../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:10% .../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:20% .../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:20% .../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:30% .../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:30% .../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:40% .../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:40% .../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:50% .../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:50% .../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:60% .../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:60% .../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:70% .../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:70% .../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:80% .../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:80% .../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:90% .../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onPostExecute: result=taskId= 2: 执行结果:100.0% .../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:90% .../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onPostExecute: result=taskId= 1: 执行结果:100.0%

从log可以看到,两个任务在并发执行。
二、AsyncTask的原理
  • 1、首先在AsyncTask被初始化时构建一个WorkerRunnable(mWorker)和一个FutureTask(mFuture),后面在执行的过程中会将封装好的mFuture放入一个线程池中执行。
  • 2、在外界调用AsyncTask.execute方法之后,开始启动AsyncTask任务,根据代码查看调用过程如下:
@MainThread public final AsyncTask< Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); }

  • 3、在execute方法中又调用了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; }

我们需要了解的是,一个AsyncTask任务有三种状态:PENDING(未开始)、RUNNING(运行中)、FINISHED(已完成)。
从上面源码我们可以看到,一个AsyncTask实例任务只能运行一次,只有是在PENDING状态下,任务才能正常运行,否则就会抛出异常。
接着在执行任务前先调用了onPreExecute方法,并将参数赋值给mWorker的参数数组,然后使用exec执行在AsyncTask初始化阶段封装好的mFuture。
  • 4、从第二步可以知道exec就是sDefaultExecutor,它是一个Executor对象,相关的源码如下:
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR; /** * An {@link Executor} that executes tasks one at a time in serial * order.This serialization is global to a particular process. */ 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是SerialExecutor对象,是一个串行的线程池,同一个进程中的所有的AsyncTask任务都在这个线程池中排队执行。
SerialExecutor的execute方法首先会将FutureTask任务加入到mTasks队列中,此时如果没有正在活动的任务就会调用scheduleNext执行下一个AsyncTask任务。
  • 5、接下来我们再回过头来看AsyncTask的构造器中在创建mWorker和mFuture时都做了些什么:
public AsyncTask(@Nullable Looper callbackLooper) { mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper() ? getMainHandler() : new Handler(callbackLooper); mWorker = new WorkerRunnable< Params, Result> () { 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; } }; 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); } } }; }

  • 6、先来分析一下上面源码中的WorkerRunnable的call方法:
WorkerRunnable的call方法中的代码很好理解,首先调用了mTaskInvoked.set(true),将任务的设为已调用状态。接着调用了doInBackground方法并获取了返回值,然后将返回值传递给postResult()方法,再看postResult方法的源码如下:
private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult< Result> (this, result)); // 在这里将doInBackground的返回结果result封装到AsyncTaskReuslt对象里面通过handler发送给主线程 message.sendToTarget(); return result; }

在此方法中通过handler发送了一条MESSAGE_POST_RESULT的消息。此handler的相关代码如下(为方便查看,适当调整了代码顺序):
private final Handler mHandler; private Handler getHandler() { return mHandler; }/** * Creates a new asynchronous task. This constructor must be invoked on the UI thread. */ public AsyncTask() { this((Looper) null); // 在这里传入了null }/** * Creates a new asynchronous task. This constructor must be invoked on the UI thread. * * @hide */ public AsyncTask(@Nullable Handler handler) { this(handler != null ? handler.getLooper() : null); // 根据上一步调用可知,handler为null }/** * Creates a new asynchronous task. This constructor must be invoked on the UI thread. * * @hide */ public AsyncTask(@Nullable Looper callbackLooper) { mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper() ? getMainHandler()// 根据上一步调用可知,callbackLooper为null,在此会调用getMainHandler() : new Handler(callbackLooper); ... }private static Handler getMainHandler() { synchronized (AsyncTask.class) { if (sHandler == null) { sHandler = new InternalHandler(Looper.getMainLooper()); } return sHandler; } }private static InternalHandler sHandler;

在上面的源码中可知,最终getHandler()方法最终是为sHandler,而sHandler是一个静态的Handler对象,sHandler的作用是将执行环境切换到主线程中,所以这就要求sHandler要在主线程中被初始化,而由于静态成员会在类加载时被初始化,这就又要求了AsyncTask类必须在主线程中加载,否则该进程中的AsyncTask任务都无法正常工作。InternalHandler相关的源码如下:
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]); // 调用AsyncTask的finish方法。 break; ... } } }private void finish(Result result) { if (isCancelled()) { onCancelled(result); // 如果任务被取消了就去调用onCancelled方法。 } else { onPostExecute(result); // 任务完成后就将执行结果传递给onPostExecute方法 } mStatus = Status.FINISHED; // 最后将状态置为FINISHED }

  • 7、接着再来看一下第五步中的FutureTask的源码
mFuture = new FutureTask< Result> (mWorker) { @Override protected void done() {// 1、在执行完mWorker的call方法之后会执行done方法。2、或者在FutureTask任务被取消后也会执行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); // 在Future任务被取消时,在此段代码中就会抛出CancellationException异常,即会执行此方法。 } } };

我们知道Future被执行后,会调用传入的mWorker的call方法,在执行完mWorker的call方法之后或者FutureTask被取消时会调用done方法,我们看到源码中在done方法中调用postResultIfNotInvoked():
private void postResultIfNotInvoked(Result result) { final boolean wasTaskInvoked = mTaskInvoked.get(); if (!wasTaskInvoked) { postResult(result); } }

在这个方法中可以看到,只有当wasTaskInvoked为false是才会发送结果,也就是说,这一步是在WorkerRunnable任务未被执行并取消的情况下才发送结果给主线程,在前几步中我们就已经知道了postResult()方法中的调用过程,最终会调用到finish方法。
private void finish(Result result) { if (isCancelled()) { onCancelled(result); // 如果任务被取消了就去调用onCancelled方法。 } else { onPostExecute(result); // 任务完成后就将执行结果传递给onPostExecute方法 } mStatus = Status.FINISHED; // 最后将状态置为FINISHED }

在任务被取消的情况下回调了onCancelled方法,至此AsyncTask异步任务执行流程基本分析完了。
三、小结
最后简单总结一下AsyncTask的原理:
  • 在AsyncTask类中有两个线程池(SerialExecutor、THREAD_POOL_EXECUTOR)和一个Handler(InternalHandler),其中SerialExecutor线程池用于对任务排队,THREAD_POOL_EXECUTOR用于真正的执行任务,InternalHandler的作用是将执行环境切换到主线程中,而AsyncTask类中的InternalHandler变量是一个静态类型的变量,这也就决定了AsyncTask类必须在主线程中加载。
  • 在调用AsyncTask的executor方法开始执行异步任务时,会首先调用onPreExecute方法通知外界任务已经开始,接着使用线程池执行前面FutureTask任务。
  • 前面所说的这个FutureTask任务是在AsyncTask初始化时被封装好的,在该任务中调用了doInBackground方法用于异步执行我们添加的耗时任务,doInBackground方法执行完毕会通过InternalHandler将返回结果发送到onPostExecute中,该方法是运行在主线程中。
 
  • 《Android开发艺术探索》
源码地址:本系列文章所对应的全部源码已同步至github,感兴趣的同学可以下载查看,结合代码看文章会更好。源码传送门本文作者:CodingBlock  文章链接:http://www.cnblogs.com/codingblock/p/8515304.html


    推荐阅读