异步消息处理机制Handler、asynctask、handlerthread、intentservice
2018-01-22 15:16
281 查看
一、Handler
1、
2、
3、
4、post(runnable)
①创建一个成员变量uiHandler,创建完成后自动绑定到了主线程
②在耗时操作执行完成之后,通知更新UI
③在源码中可以看到,底层也是调用的sendmessage方法,只是对该方法进行了封装
5、sendMessage方法
①创建handler对象,并实现方法
②发送消息
6、handler的消息机制
①handler只能发送到与之相关联的线程中,
②在构造函数中创建了looper,并通过looper创建了messagequeue,这样在构造方法当中,handler已经和looper和messagequeque进行了关联,而messageque又通过looper来管理
③looper的获取
在looper的prepareMainLooper中,调用了prepare方法
在prepare方法中创建了一个looper对象,并将它设置给了threadlocal,这样就保证了每一个线程looper的唯一性
④looper.loope()方法,实际上就是创建了一个死循环,并且不断地从队列中获取消息并处理消息的过程
dispatchMessage用于消息的分发
message中的target实际上就是一个handler
⑤对looper的总结
在handler的构造方法中创建了looper,在looper的prepare方法中创建looper并把它保存到了threadlocal中,通过looper.loop()开启循环,来进行消息的分发,最终调用了msg.target.dispatchMessage方法,实际上又把消息传递给了handler。
通过handler将消息传递给了消息队列,而消息队列又将消息分发给了handler来处理。
handler的作用:一个是接收消息与发送消息,另一个是处理消息
⑥handler的dispatch方法
实际上就是一个中转器。msg的callback实际上就是一个runnable。
不管handler以何种方式发送消息,都会通过looper不断地从消息队列中获取消息,然后交由handler.dispachMessage这个方法进行处理
handleCallback世界上就是走了callback的run方法
⑦
7、handler的内存泄漏及解决办法
①
②从源码中可以看到,所创建的handler不是静态内部类,所以会持有handlerwithruannableactivity这个引用,当activity要被回收的时候,由于handler可以在做耗时的操作,导致handler还没有被释放,handler所持有的activity的引用也不能被释放,导致activity没有被回收,而停留在堆内存当中,造成了内存泄漏
③解决办法:
将handler设置为静态内部类
在activity的onDestroy方法中,调用handler的removeCallback()方法
这两步就可以解决内存泄漏
二、AsyncTask
1、AsyncTask只能做一些耗时比较短的操作,如果要做一些耗时比较长的操作,还是需要使用线程池。由于集成了handler,可以很方便地在ui线程和子线程中进行切换
2、
3、代码
①
②三个参数
第一个参数Integer:表示执行Asynctask时所需要执行的参数,可用于在后台执行任务时使用
第二个参数Integer表示在后台执行任务时显示当前的进度
第三个参数String表示result,在处理结果时使用
③五个方法
构造方法
onPreExecute:运行在主线程,在异步任务开始前执行
doInBackgroud:处理耗时操作,在onPreExecute执行之后执行
onProgressUpdate:在doInBackgroud方法之后执行
onPostExecute:后台计算完成之后调用
4、
5、
①
②内存泄漏:原因是非静态的内部类持有外面类的引用,在doInbackgroud方法中执行了耗时操作,从而持有activity的引用,不能被gc回收,导致的内存泄漏。解决方法:将AsyncTask设置为静态的,同时在静态的AsyncTask中持有外部activity的弱引用,让activity需要被回收的时候可以顺利被回收。同时,可以在activity的ondestroy方法中执行asynctask的cancle方法进行finish
③生命周期:asynctask并不是随着activity的销毁而销毁,因为耗时任何在doinbackgroud方法中执行,如果没有主动调用asynctask的cancel方法是不会被销毁的。这样可能会导致asynctask在activity在销毁之前崩溃。这样必须在activity的ondestroy方法中调用asynctask的cancle方法来保证程序的稳定
④结果丢失:与生命周期类似,主要是在activity旋转或activity由于内存不够被后台杀掉,导致activity被重新创建而之前创建的asynctask会持有之前的activity的引用,但是引用已经无效,此时调用asynctask的onpostexecute方法不会再生效。这就是asynctask结果丢失的原因
⑤并行或串行:在Android 1.6之前的版本,asynctask都是串行,会把所有的任务一串一串地放到线程池中有序地执行。在1.6到2.3的版本之后,改成了并行。但是在2.3之后,为了维护稳定,又改成了串行。但是还是可以执行并行,想执行并行的时候excute.onExcute()这个方法。一般建议,只使用串行,这样能保证线程池的稳定
三、HandlerThread
1、
2、
在子线程中不能开启handler的原因:handler的sendmessage和post(ruannable)都需要一个消息队列来保存它所发送的消息,而子线程中默认是没有开启looper轮询器的,而消息队列又是由looper进行管理的。所以,在子线程如果想创建一个handler发生消息,是没有关联的messagequeue来存储消息,所以会抛出异常。如果想在子线程中创建一个handler,必须自己初始化一个looper,然后再通过looper.loops()开启一个循环,才能创建handler
3、
4、源码
①继承了thread,onLooperPrepared()方法必须在开启looper.loop()之前调用
②run方法是每一个thread都必须复写的一个方法
Looper.prepare():初始化一个looper
onLooperPrepared():自己重写
Looper.loop():开启循环
③getLooper()
以阻塞等待的方式进行创建
④
quit和quitsafely都是使looper退出消息队列,但是quitesafely更加安全,但是效率不高
四、IntentService
1、继承service,比service优先级高,串行执行
2、使用方法
①创建一个类集成intentservice
构造方法和onHandleIntent必须实现
②最后,通过handler更新ui
③开启intentservice,虽然开启了多次,但是实例只有一个
3、
intentservice的源码
①继承自service
②
HanderThread:在onCreate()方法中,创建了一个HandlerThread,说明内部就是使用handlerthread进行消息传递的
ServiceHandler:继承了handler的handler
Looper:传入了handlerthread的looper对象
③
intentservice启动后会调用onStartCommand方法,这个方法里只是调用了一个onStart()方法
④onStart()方法通过sendMessage()方法传递了一个消息
⑤servicehandler的handmessage方法
实际上调用了handlerservice的handmessage方法,方法结束后停止了服务,stopself()方法中传入了参数,因为如果不传入参数,会立即终止,如果传入了参数,会等待所有的参数都执行完后再终止
⑥handleMessage中会回调onHandleIntent方法,该方法是一个抽象方法,该方法执行的是异步任务,是一个异步方法,原因是有一个servicehandler方法是处理异步任务的。当handlerintent方法执行完毕后,intentservice会立即销毁,但是如果里面有很多任务的话,会等待最后一个任务执行完后再销毁
⑦
注:
1、参考资料:https://coding.imooc.com/lesson/101.html#mid=3575
1、
2、
3、
4、post(runnable)
①创建一个成员变量uiHandler,创建完成后自动绑定到了主线程
②在耗时操作执行完成之后,通知更新UI
③在源码中可以看到,底层也是调用的sendmessage方法,只是对该方法进行了封装
5、sendMessage方法
①创建handler对象,并实现方法
②发送消息
6、handler的消息机制
①handler只能发送到与之相关联的线程中,
②在构造函数中创建了looper,并通过looper创建了messagequeue,这样在构造方法当中,handler已经和looper和messagequeque进行了关联,而messageque又通过looper来管理
③looper的获取
在looper的prepareMainLooper中,调用了prepare方法
在prepare方法中创建了一个looper对象,并将它设置给了threadlocal,这样就保证了每一个线程looper的唯一性
④looper.loope()方法,实际上就是创建了一个死循环,并且不断地从队列中获取消息并处理消息的过程
dispatchMessage用于消息的分发
message中的target实际上就是一个handler
⑤对looper的总结
在handler的构造方法中创建了looper,在looper的prepare方法中创建looper并把它保存到了threadlocal中,通过looper.loop()开启循环,来进行消息的分发,最终调用了msg.target.dispatchMessage方法,实际上又把消息传递给了handler。
通过handler将消息传递给了消息队列,而消息队列又将消息分发给了handler来处理。
handler的作用:一个是接收消息与发送消息,另一个是处理消息
⑥handler的dispatch方法
实际上就是一个中转器。msg的callback实际上就是一个runnable。
不管handler以何种方式发送消息,都会通过looper不断地从消息队列中获取消息,然后交由handler.dispachMessage这个方法进行处理
handleCallback世界上就是走了callback的run方法
⑦
7、handler的内存泄漏及解决办法
①
②从源码中可以看到,所创建的handler不是静态内部类,所以会持有handlerwithruannableactivity这个引用,当activity要被回收的时候,由于handler可以在做耗时的操作,导致handler还没有被释放,handler所持有的activity的引用也不能被释放,导致activity没有被回收,而停留在堆内存当中,造成了内存泄漏
③解决办法:
将handler设置为静态内部类
在activity的onDestroy方法中,调用handler的removeCallback()方法
这两步就可以解决内存泄漏
二、AsyncTask
1、AsyncTask只能做一些耗时比较短的操作,如果要做一些耗时比较长的操作,还是需要使用线程池。由于集成了handler,可以很方便地在ui线程和子线程中进行切换
2、
3、代码
①
②三个参数
第一个参数Integer:表示执行Asynctask时所需要执行的参数,可用于在后台执行任务时使用
第二个参数Integer表示在后台执行任务时显示当前的进度
第三个参数String表示result,在处理结果时使用
③五个方法
构造方法
onPreExecute:运行在主线程,在异步任务开始前执行
doInBackgroud:处理耗时操作,在onPreExecute执行之后执行
onProgressUpdate:在doInBackgroud方法之后执行
onPostExecute:后台计算完成之后调用
4、
5、
①
②内存泄漏:原因是非静态的内部类持有外面类的引用,在doInbackgroud方法中执行了耗时操作,从而持有activity的引用,不能被gc回收,导致的内存泄漏。解决方法:将AsyncTask设置为静态的,同时在静态的AsyncTask中持有外部activity的弱引用,让activity需要被回收的时候可以顺利被回收。同时,可以在activity的ondestroy方法中执行asynctask的cancle方法进行finish
③生命周期:asynctask并不是随着activity的销毁而销毁,因为耗时任何在doinbackgroud方法中执行,如果没有主动调用asynctask的cancel方法是不会被销毁的。这样可能会导致asynctask在activity在销毁之前崩溃。这样必须在activity的ondestroy方法中调用asynctask的cancle方法来保证程序的稳定
④结果丢失:与生命周期类似,主要是在activity旋转或activity由于内存不够被后台杀掉,导致activity被重新创建而之前创建的asynctask会持有之前的activity的引用,但是引用已经无效,此时调用asynctask的onpostexecute方法不会再生效。这就是asynctask结果丢失的原因
⑤并行或串行:在Android 1.6之前的版本,asynctask都是串行,会把所有的任务一串一串地放到线程池中有序地执行。在1.6到2.3的版本之后,改成了并行。但是在2.3之后,为了维护稳定,又改成了串行。但是还是可以执行并行,想执行并行的时候excute.onExcute()这个方法。一般建议,只使用串行,这样能保证线程池的稳定
三、HandlerThread
1、
2、
在子线程中不能开启handler的原因:handler的sendmessage和post(ruannable)都需要一个消息队列来保存它所发送的消息,而子线程中默认是没有开启looper轮询器的,而消息队列又是由looper进行管理的。所以,在子线程如果想创建一个handler发生消息,是没有关联的messagequeue来存储消息,所以会抛出异常。如果想在子线程中创建一个handler,必须自己初始化一个looper,然后再通过looper.loops()开启一个循环,才能创建handler
3、
4、源码
①继承了thread,onLooperPrepared()方法必须在开启looper.loop()之前调用
②run方法是每一个thread都必须复写的一个方法
Looper.prepare():初始化一个looper
onLooperPrepared():自己重写
Looper.loop():开启循环
③getLooper()
以阻塞等待的方式进行创建
④
quit和quitsafely都是使looper退出消息队列,但是quitesafely更加安全,但是效率不高
四、IntentService
1、继承service,比service优先级高,串行执行
2、使用方法
①创建一个类集成intentservice
构造方法和onHandleIntent必须实现
②最后,通过handler更新ui
③开启intentservice,虽然开启了多次,但是实例只有一个
3、
intentservice的源码
①继承自service
②
HanderThread:在onCreate()方法中,创建了一个HandlerThread,说明内部就是使用handlerthread进行消息传递的
ServiceHandler:继承了handler的handler
Looper:传入了handlerthread的looper对象
③
intentservice启动后会调用onStartCommand方法,这个方法里只是调用了一个onStart()方法
④onStart()方法通过sendMessage()方法传递了一个消息
⑤servicehandler的handmessage方法
实际上调用了handlerservice的handmessage方法,方法结束后停止了服务,stopself()方法中传入了参数,因为如果不传入参数,会立即终止,如果传入了参数,会等待所有的参数都执行完后再终止
⑥handleMessage中会回调onHandleIntent方法,该方法是一个抽象方法,该方法执行的是异步任务,是一个异步方法,原因是有一个servicehandler方法是处理异步任务的。当handlerintent方法执行完毕后,intentservice会立即销毁,但是如果里面有很多任务的话,会等待最后一个任务执行完后再销毁
⑦
注:
1、参考资料:https://coding.imooc.com/lesson/101.html#mid=3575
相关文章推荐
- android os;异步消息处理机制:AsyncTask和Handler
- 异步消息处理机制-Handler、AsyncTask
- 线程相关——HandlerThread、IntentService、ResultReceiver:结果接收者、AsyncTask:异步任务、Android中处理线程间通信的方式
- Service初探与异步消息处理机制
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
- Android Handler 异步消息处理机制的妙用 创建强大的图片加载类
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
- ANDROID_MARS学习笔记_S01原始版_008_Handler(异步消息处理机制)
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
- Android异步消息处理机制Handler
- Android Handler 异步消息处理机制的妙用 创建强大的图片加载类
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
- 深入理解异步消息处理机制Message,handler,MessageQueue,looper
- Android多线程----异步消息处理机制之Handler详解
- Android 异步消息处理机制之Handler、Message、Looper
- Android线程之异步消息处理机制(二)——Message、Handler、MessageQueue和Looper
- Android开发之异步消息处理机制AsyncTask
- Android多线程----异步消息处理机制之Handler详解
- Android异步消息处理机制 Handler、Looper、Message