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

最终回到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线程的目的。

内部类带来的问题
为什么会有内存泄漏
内部类的引用被外部类以外的其他类引用时,就会造成内部类和外部类无法被GC回收的情况,即使外部类没有被引用,因为内部类持有指向外部类的引用。
handler作为内部类,被message引用,而message又被looper里引用到,那么handler持有的外部类就不会被销毁。
解决办法
- 给activity添加弱引用
- 在activity销毁时,将handler置空,message置空
- 静态内部类