AsyncTask
是 Android 系统的一个轻量级异步类,它可以在线程池中执行后台任务,并且把执行的进度和结果传递给主线程。默认串行执行,已废弃。
优点:
使用简单;
子线程执行耗时操作,主线程更新进度和结果;
缺点:
系统兼容性问题;
不能真正取消任务,调用 cancel(true) 只是给任务做一下标记,等任务执行完成后回调 onCancelled() 方法;
一个 AsyncTask 实例只能执行一次任务;
内存泄漏问题;
AsyncTask 的泛型参数 1 2 3 4 5 6 public abstract class AsyncTask <Params, Progress, Result> {}
Params: 开始异步任务执行时传入的参数;
Progress: 异步任务执行过程中,返回下载进度值的类型;
Result: 异步任务执行完成后,返回的结果类型;
如果 AsyncTask 确定不需要传递具体参数,那么这三个泛型参数可以用 Void 来代替。
核心方法
onPreExecute() 运行在主线程。会在任务开始执行之前调用,用于进行 UI 初始化操作,比如显示一个进度条对话框等。
Result doInBackground(Params… params) 运行在子线程。抽象方法,子类重写,用于执行耗时操作。
onProgressUpdate(Progress… values) 运行在主线程。任务在执行过程中,可以通过此方法将任务进度发布到 UI 线程,比如显示进度条。必须调用publishProgress(Progress... values)
方法。
onPostExecute(Result result) 运行在主线程。任务执行成功后,返回的数据会作为参数传递到此方法中。比如说提醒任务执行的结果,以及关闭掉进度条对话框等。
onCancelled 运行在主线程。任务执行失败后的回调方法。
线程池 AsyncTask 内置了两个线程池,分别是串行的 SERIAL_EXECUTOR
和并行的 THREAD_POOL_EXECUTOR
。其中 SerialExecutor 线程池用于任务的排队
,让需要执行的任务按顺序排列,THREAD_POOL_EXECUTOR
线程池才真正地执行任务。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 private static final int CORE_POOL_SIZE = 1 ;private static final int MAXIMUM_POOL_SIZE = 20 ;private static final int KEEP_ALIVE_SECONDS = 3 ;public static final Executor SERIAL_EXECUTOR = new SerialExecutor ();private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;public static final Executor THREAD_POOL_EXECUTOR;static { ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor ( CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS, new SynchronousQueue <Runnable>(), sThreadFactory); threadPoolExecutor.setRejectedExecutionHandler(sRunOnSerialPolicy); THREAD_POOL_EXECUTOR = threadPoolExecutor; } 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); } } }
SerialExecutor 的作用是保存执行的任务和按 FIFO 的优先级串行调度任务,如果前面的任务比较耗时,后面的任务会响应不及时;
任务是在 THREAD_POOL_EXECUTOR 线程池中执行的,可以通过 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params)
执行并行任务;
拒绝执行策略 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 private static final int BACKUP_POOL_SIZE = 5 ;private static final RejectedExecutionHandler sRunOnSerialPolicy = new RejectedExecutionHandler () { public void rejectedExecution (Runnable r, ThreadPoolExecutor e) { synchronized (this ) { if (sBackupExecutor == null ) { sBackupExecutorQueue = new LinkedBlockingQueue <Runnable>(); sBackupExecutor = new ThreadPoolExecutor ( BACKUP_POOL_SIZE, BACKUP_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS, sBackupExecutorQueue, sThreadFactory); sBackupExecutor.allowCoreThreadTimeOut(true ); } } sBackupExecutor.execute(r); } };
THREAD_POOL_EXECUTOR 执行拒绝策略时,会创建新的线程池重新执行任务。
取消任务 AsyncTask 还提供了 onCancelled()
方法,它同样在主线程中执行。当异步任务调用 cancel() 取消任务时,onCancelled() 会被调用,而不是 onPostExecute() 方法。cancel() 方法并不是真正的取消任务
,还是要等到任务执行完成。
1 2 3 4 5 6 7 8 9 10 11 12 13 public final boolean cancel (boolean mayInterruptIfRunning) { mCancelled.set(true ); return mFuture.cancel(mayInterruptIfRunning); } private void finish (Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; }
我们需要在 doInBackground() 判断终止任务,和终止一个线程类似,调用 interrupt() 方法,只是进行标记为中断,需要在线程内部进行标记判断然后中断线程。
使用 AsyncTask 的注意事项
版本兼容问题;
execute(Params… params) 方法必须在 UI 线程中调用;
不要手动调用 AsyncTask 的几个回调方法;
一个 AsyncTask 任务只能执行一次,如果执行多次时任务的状态时 RUNNING 或 FINISHED,会抛出异常;
任务取消后并不会立即停止,而是等到任务完成后回调 onCancelled() 方法;
AsyncTask 不应该与任何组件绑定生命周期,所以在执行 AsyncTask 时,最好在 Activity/Fragment 的 onDestory()调用 cancel(boolean),避免 crash 或内存泄露。
参考 [1] AsyncTask - Developer