您的位置:首页 > 其它

异步消息处理机制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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐