Android异步处理机制AsyncTask的理解
在Android中,由于主线程的诸多限制,像网络请求等一些耗时的操作我们必须在子线程中运行。我们往往会通过new Thread来开启一个子线程,待子线程操作完成以后通过Handler切换到主线程中运行。这么以来我们无法管理我们所创建的子线程,并且无限制的创建子线程,它们相互之间竞争,很有可能由于占用过多资源而导致死机或者OOM。所以在Java中为我们提供了线程池来管理我们所创建的线程。
而AsyncTask就是这么个环境下产生的。它本质上是一个静态的线程池(封装了THREAD_POOL_EXECUTOR异步线程池和SERIAL_EXECUTOR同步线程池和Handler),AsyncTask派生出的子类可以实现不同的异步任务,这些任务都是提交到静态的线程池中执行。线程池中的工作线程执行doInBackground(mParams)方法执行异步的任务。当任务状态改变后,工作线程向UI线程发送消息,AsyncTask内部的InternalHandler响应这些消息,并调用相关的回调函数。
下面是三种泛型:
- Params表示用于AsyncTask执行任务的参数的类型
- Progress表示在后台线程处理的过程中,可以阶段性地发布结果的数据类型
- Result表示任务全部完成后所返回的数据类型
.AsyncTask的核心方法:
** onPreExecute()**
这个方法会在后台任务开始执行之间调用,在主线程执行。用于进行一些界面上的初始化操作,比如显示一个进度条对话框等。
doInBackground(Params...)
这个方法中的所有代码都会在子线程中运行,我们应该在这里去处理所有的耗时任务。
任务一旦完成就可以通过return语句来将任务的执行结果进行返回,如果AsyncTask的第三个泛型参数指定的是Void,就可以不返回任务执行结果。注意,在这个方法中是不可以进行UI操作的,如果需要更新UI元素,比如说反馈当前任务的执行进度,可以调用publishProgress(Progress...)方法来完成。
onProgressUpdate(Progress...)
当在后台任务中调用了publishProgress(Progress...)方法后,这个方法就很快会被调用,方法中携带的参数就是在后台任务中传递过来的。在这个方法中可以对UI进行操作,在主线程中进行,利用参数中的数值就可以对界面元素进行相应的更新。
onPostExecute(Result)
当doInBackground(Params...)执行完毕并通过return语句进行返回时,这个方法就很快会被调用。返回的数据会作为参数传递到此方法中,可以利用返回的数据来进行一些UI操作,在主线程中进行,比如说提醒任务执行的结果,以及关闭掉进度条对话框等。
上面几个方法的调用顺序:
onPreExecute() --> doInBackground() --> publishProgress() --> onProgressUpdate() --> onPostExecute()
如果不需要执行更新进度则为onPreExecute() --> doInBackground() --> onPostExecute(),
除了上面四个方法,AsyncTask还提供了onCancelled()方法,它同样在主线程中执行,当异步任务取消时,onCancelled()会被调用,这个时候onPostExecute()则不会被调用,但是要注意的是,AsyncTask中的cancel()方法并不是真正去取消任务,只是设置这个任务为取消状态,我们需要在doInBackground()判断终止任务。就好比想要终止一个线程,调用interrupt()方法,只是进行标记为中断,需要在线程内部进行标记判断然后中断线程。
使用AsyncTask的注意事项:
①异步任务的实例必须在UI线程中创建,即AsyncTask对象必须在UI线程中创建。
②execute(Params... params)方法必须在UI线程中调用。
③不要手动调用onPreExecute(),doInBackground(Params...params),onProgressUpdate(Progress... values),onPostExecute(Result result)这几个方法。
④不能在doInBackground(Params... params)中更改UI组件的信息。
⑤一个任务实例只能执行一次,如果执行第二次将会抛出异常。
AsyncTask使用不当的后果
1.)生命周期
AsyncTask不与任何组件绑定生命周期,所以在Activity/或者Fragment中创建执行AsyncTask时,最好在Activity/Fragment的onDestory()调用 cancel(boolean);
2.)内存泄漏
如果AsyncTask被声明为Activity的非静态的内部类,那么AsyncTask会保留一个对创建了AsyncTask的Activity的引用。如果Activity已经被销毁,AsyncTask的后台线程还在执行,它将继续在内存里保留这个引用,导致Activity无法被回收,引起内存泄露。
3.) 结果丢失
屏幕旋转或Activity在后台被系统杀掉等情况会导致Activity的重新创建,之前运行的AsyncTask(非静态的内部类)会持有一个之前Activity的引用,这个引用已经无效,这时调用onPostExecute()再去更新界面将不再生效。
AsyncTask里面的两个线程池:
1AsyncTask里面有THREAD_POOL_EXECUTOR和SERIAL_EXECUTOR两种方式来异步执行任务;THREAD_POOL_EXECUTOR是异步的,而SERIAL_EXECUTOR任务是顺序执行的。
2. THREAD_POOL_EXECUTOR如果添加的任务过多,没有及时处理的话,会导致程序崩溃,它的队列size是128;它的调度规则是核心池大小,队列大小,以及最大线程数和异常处理Handler来决定的。
3. SERIAL_EXECUTOR本质是在THREAD_POOL_EXECUTOR的基础上添加一个mTasks的集合来保证任务的顺序执行。
更多相关文章
- Android(安卓)组件之一(Service)
- Android基础笔记(十一)- Service基础和注意事项以及Activity与Serv
- Android(安卓)如何获取当前Activity实例对象?
- Android(安卓)AsyncTask 异步任务之源码解析
- Android应用资源的使用方法(数组、颜色、尺寸、字符串、布尔、整
- 源码阅读分析 - View的Touch事件分发
- 随Android生命周期解绑Rxjava订阅的简单流式方法
- Android(安卓)Touch点击事件源码分析
- 【原创】Android(安卓)系统稳定性 - ANR(三)