AsyncTask是什么?
AsyncTask是Google提供的一个轻量级的异步任务类,它可以在线程池中执行一些耗时的后台任务(线程池异步加载),并把任务执行的进度和最终执行的结果传递给主线程中(Handler机制),从而实现UI界面的更新。
AsyncTask的原理
- AsyncTask中包含着两个线程池SerialExecutor(可串行线程池)和一个HREAD_POOL_EXECUTOR,外加一个Handler(InternalHandler),其中的SerialExecutor主要用于任务的排队,而HREAD_POOL_EXECUTOR线程池才是真正的用于后台任务的执行,InternalHandler则是用于线程的切换(将执行环境从线程池切换到主线程)。
- sHandler是一个静态的Handler对象,为了能够将执行环境切换到UI线程,这一点就要求sHandler这个对象必须在主线程中创建(消息在哪个线程中接收,Handler就应该在这个线程中创建)。由于静态成员会在加载类的时候进行初始化,因此这就变相要求AsyncTask的类必须在主线程中加载,否则同一个进程中的AsyncTask都无法正常工作。
关于线程池
AsyncTask对应的线程池ThreadPoolExecutor都是进程范围内共享的,并且是静态static的,所以是Asynctask控制着进程范围内所有的子类实例。由于限制的存在,当使用默认线程池的时候,如果线程数量超过了线程池的最大容量,线程池就会爆掉。为了解决这一局限,在使用Asynctask时候可以尝试自定义线程池。
AsyncTask里面是一个核心线程数为CPU+1的线程池,最大线程数为CPU*2+1,工作队列的长度为128的线程池,线程等待队列的最大等待数为28,但是可以自定义线程池。线程池是由AsyncTask来处理的,线程池允许tasks并行运行,需要注意的是并发情况下数据的一致性问题,新数据可能会被老数据覆盖掉。所以希望tasks能够串行运行的话,使用SERIAL_EXECUTOR。
AsyncTask在不同SDK版本下的区别
调用AsyncTask的execute方法不能立即执行程序的原因及改善方案通过查阅文档发现,AsyncTask首次引入时,异步任务是在一个独立的线程中顺序执行的,也就是说一次只执行一个任务,不能并行的执行,从1.6开始,AsyncTask引入了线程池,支持同时执行5个异步任务,也就是说只能有5个线程运行,超过的线程只能等待,等待前的线程直到某个执行完了才被调度和运行,2.3以前的版本无法解决。如果你需要大量的后台线程去执行任务,那么只能放弃AsyncTask,自己创建线程池来管理Thread。从Android3.0开始对AsyncTask的API作出了调整:每次只启动一个线程执行任务,完了之后再执行第二个任务,也就是相当于只有一个后台线程在执行所提交的任务。
AsyncTask的缺陷
AsyncTask虽然能很好的为我们执行后台耗时任务,同事完成线程的调度,但是在使用时的一切不注意同样会给我们带来一些问题。
- 生命周期
在使用AsyncTask的时候,不要认为在一个Activity中创建一个AsyncTask,它就会随着Activity的销毁而销毁。AsyncTask会一直执行,直到doInBackground()方法执行完毕,然后如果cancel(boolean)被调用,那么onCancelled(Result result)方法会被执行;否则执行onPostExecute(Result result)方法。如果我们的Activity销毁之前,没有取消AsyncTask,这样有可能让应用crash。因为它想要处理的view已经不存在了。所有,我们必须确保在销毁Activity之前取消任务。 - 内存泄漏
如果AsyncTask被声明为Activity的非静态内部类,那么AsyncTask会保留一个对Activity的引用。如果Activity已经被销毁,AsyncTask的后台线程还在执行,它将继续在内存里保留这个引用,导致Activity无法被回收,引起内存泄漏的问题 - 结果丢失
屏幕旋转或者Activity在后台被系统杀掉等情况会导致Activity的重新创建,之前运行的AsyncTask会持有一个之前的Activity的引用,这个引用已经无效,这时调用onPostExecute()再去更新界面将不会生效。 - 并行串行
Android1.6之前,AsyncTask是串行的,之后采用线程池处理并行任务,但从Android3.0开始,为了避免AsyncTask所带来的并非错误,有采用一个线程来串行执行任务,可以使用executeOnExecutor()方法来并行地执行任务。
网友评论