在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的集合来保证任务的顺序执行。

 

 

 

 


 

 

 

 

 

 

 

 

 

 

 

更多相关文章

  1. Android(安卓)组件之一(Service)
  2. Android基础笔记(十一)- Service基础和注意事项以及Activity与Serv
  3. Android(安卓)如何获取当前Activity实例对象?
  4. Android(安卓)AsyncTask 异步任务之源码解析
  5. Android应用资源的使用方法(数组、颜色、尺寸、字符串、布尔、整
  6. 源码阅读分析 - View的Touch事件分发
  7. 随Android生命周期解绑Rxjava订阅的简单流式方法
  8. Android(安卓)Touch点击事件源码分析
  9. 【原创】Android(安卓)系统稳定性 - ANR(三)

随机推荐

  1. Android(安卓)集成微信支付和支付宝支付
  2. MonoDroid学习笔记(一)—— 搭建MonoDroid
  3. Android开发实践:WIFI连接功能的封装
  4. Android查看wifi密码——通过ADB
  5. android 欢迎界面翻页效果,仿微信第一次登
  6. 如何在Android实现桌面清理内存简单Widge
  7. setOntouchListener和setOnKeyListener
  8. Android与线程
  9. Android中怎么破解游戏之修改金币数
  10. ANDROID Bionic C DOCS