什么是AsyncTask
- AsyncTask内部封装了Thread和Handler,可以让我们在后台进行计算或者把计算的结果及时更新到UI上。
- AsyncTask的作用就是简化的Thread + Handler,让我们能够通过更少的代码来完成一样的功能。
- AsyncTask 是一个抽象的泛型类,它提供了 Params、Progress 和 Result 这三个 泛型参数,其中 Params 表示参数的类型,Progress 表示后台任务的执行进度和 类型,而 Result 则表示后台任务的返回结果的类型,如果 AsyncTask 不需要传 递具体的参数,那么这三个泛型参数可以用 Void 来代替。
AsyncTask原理
- AsyncTask 中 有 两 个 线 程 池 ( SerialExecutor 和 THREAD_POOL_EXECUTOR)和一个Handler(InternalHandler),其中 线程池 SerialExecutor 用于任务的排队,而线程池 THREAD_POOL_EXECUTOR 用于真正地执行任务,InternalHandler 用于将执行环境从线程池切换到主线程。
- sHandler 是一个静态的 Handler 对象,为了能够将执行环境切换到主线 程,这就要求 sHandler 这个对象必须在主线程创建。由于静态成员会在 加载类的时候进行初始化,因此这就变相要求 AsyncTask 的类必须在主线 程中加载,否则同一个进程中的 AsyncTask 都将无法正常工作。
使用AsyncTask的规则
- AsyncTask 的类必须在 UI 线程加载(从 4.1 开始系统会帮我们自动完成)。AsyncTask 对象必须在 UI 线程创建。
- execute 方法必须在 UI 线程调用。
- 不要在你的程序中去直接调用 onPreExecute(), onPostExecute, doInBackground, onProgressUpdate 方法。
- 一个 AsyncTask 对象只能执行一次,即只能调用一次 execute 方法,否则会报运行时异常。
- AsyncTask 不是被设计为处理耗时操作的,耗时上限为几秒钟,如果要做长耗时操作,强烈建议你使用 Executor,ThreadPoolExecutor 以及 FutureTask。
- 在 1.6 之前,AsyncTask 是串行执行任务的,1.6 的时候 AsyncTask 开始采用线程池里处理并行任务,但是从 3.0 开始,为了避免 AsyncTask 所带来的并发错误,AsyncTask 又采用一个线程来串行执行任务。
- asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, Params... params),通过这个方法我们可以自定义 AsyncTask 的执行方式,串行 or 并行,甚至采用自己的Execuor。
- execute(Runnable runnable),这是 AsyncTask 提供的一个静态方法,方便我们直接执行一个 runnable。
AsyncTask里的线程池
AsyncTask 对应的线程池 ThreadPoolExecutor 都是进程范围内共享的,且都是static 的,所以是 Asynctask 控制着进程范围内所有的子类实例。由于这个限制的存在,当使用默认线程池时,如果线程数超过线程池的最大容量,线程池就会爆掉(3.0 后默认串行执行,不会出现个问题)。针对这种情况,可以尝试自定义线程池,配合 Asynctask 使用。
AsyncTask里面线程池是一个核心线程数为CPU + 1,最大线程数为CPU * 2 + 1, 工作队列长度为128的线程池,线程等待队列的最大等待数为 28,但是可以自定义线程池。线程池是由 AsyncTask 来处理的,线程池允许 tasks 并行运行,需要注意的是并发情况下数据的一致性问题,新数据可能会被老数据覆盖掉。所以希望 tasks 能够串行运行的话,使用 SERIAL_EXECUTOR。
AsyncTask生命周期问题
- 一个在 Activity 中创建的 AsyncTask 不会随着 Activity 的销毁而销毁。AsyncTask 会一直执行,直到 doInBackground()方法 执行完毕 。
- 如果 cancel(boolean)被调用,那么 onCancelled(Result result) 方法会被执行。否则,执行onPostExecute(Result result)方法 。
- 必须确保在销毁活动之前取消任务。 总之,我们使用 AsyncTask 需要确保 AsyncTask 正确的取消。
AsyncTask内存泄漏问题
如果 AsyncTask 被声明为 Activity 的非静态内部类,那么 AsyncTask 会保留一个 对 Activity 的引用。如果 Activity 已经被销毁,AsyncTask 的后台线程还在执行, 它将继续在内存里保留这个引用,导致 Activity 无法被回收,引起内存泄漏。
AsyncTask结果丢失问题
屏幕旋转或 Activity 在后台被系统杀掉等情况会导致 Activity 的重新创建,之前运行的 AsyncTask 会持有一个之前 Activity 的引用,这个引用已经无效,这时调用 onPostExecute()再去更新界面将不再生效。
AsyncTask并行还是串行
在 Android1.6 之前的版本,AsyncTask 是串行的,在 1.6 之后的版本,采用线程 池处理并行任务,但是从 Android 3.0 开始,为了避免 AsyncTask 所带来的并发 错误,又采用一个线程来串行执行任务。可以使用 executeOnExecutor()方法来并行地执行任务。