Handler简要笔记

1. handler是什么

handler是Android给我们提供用来更新UI的一套机制,也是一套消息处理机制,我们可以发消息,也可以通过它处理消息。

在Android中,只有主线程(UI线程)才能去进行更新UI的操作,而不允许在其它线程去进行UI更新就会出现错误。但我们可以通过handler来在线程中进行UI更新的操作。

2. 为什么要用到handler

最根本的目的就是为了解决多线程并发的问题!

打个比方,如果在一个activity中有多个线程,并且没有加锁,就会出现界面错乱的问题。但是如果对这些更新UI的操作都加锁处理,又会导致性能下降。处于对性能的问题考虑,Android给我们提供这一套更新UI的机制我们只需要遵循这种机制就行了。不用再去关系多线程的问题,所有的更新UI的操作,都是在主线程的消息队列中去轮训的。

假如我们现在有这么一个场景:异步请求网络数据后我要根据数据来刷新界面的一些信息,如何才能及时更新呢?

可能有的同学会说:用回调!

但是子线程的回调还是在子线程,如果这样进行UI操作是Android不允许的,所以单单的回调是不行的。然而一看handler这用法,不是回调是啥?

其实handler确实是基于回调的,但这个回调却不是传递回子线程,而是传递给了主线程的消息队列中,这些消息排好队依次执行在主线程中,这样就避免了冲突。

3. handler流程及问题

handler流程,如何切换回主线程

其实在回答为什么会产生内存泄漏这问题的时候我想先回顾一下handler机制的流程:

图源:https://blog.csdn.net/c6E5UlI1N/article/details/79724023

  1. Message
    消息,即线程间传递的对象,传递的信息包含在其中。例如后台线程在处理数据完毕后需要更新UI,则可发送一条包含更新信息的Message给UI线程。
  2. Message Queue
    消息队列,用来存放通过Handler发布的消息,按照先进先出执行。
  3. Handler
    Handler是Message的主要处理者,负责将Message添加到消息队列以及对消息队列中的Message进行处理。
  4. Looper
    循环器,扮演Message Queue和Handler之间桥梁的角色,循环取出Message Queue里面的Message,并交付给相应的Handler进行处理。

640?wx_fmt=png&wxfrom=5&wx_lazy=1

最终回到Handler是如何实现线程之间的切换的呢?例如现在有A、B两个线程,在A线程中有创建了handler,然后在B线程中调用handler发送一个message。(不是每一个activity都是一个新的ui线程(主线程),只有一个主线程,对activity进行引用使用?大概)

通过上面的分析我们可以知道,当在A线程中创建handler的时候,同时创建了MessageQueue与Looper,Looper在A线程中调用loop进入一个无限的for循环从MessageQueue中取消息,当B线程调用handler发送一个message的时候,会通过msg.target.dispatchMessage(msg);将message插入到handler对应的MessageQueue中,Looper发现有message插入到MessageQueue中,便取出message执行相应的逻辑,因为Looper.loop()是在A线程中启动的,所以则回到了A线程,达到了从B线程切换到A线程的目的。

640?wx_fmt=png

内部类带来的问题

为什么会有内存泄漏

内部类的引用被外部类以外的其他类引用时,就会造成内部类和外部类无法被GC回收的情况,即使外部类没有被引用,因为内部类持有指向外部类的引用。

handler作为内部类,被message引用,而message又被looper里引用到,那么handler持有的外部类就不会被销毁。

解决办法

  1. 给activity添加弱引用
  2. 在activity销毁时,将handler置空,message置空
  3. 静态内部类

版权声明:本文为qq_40589292原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。