Handler是什么
个人理解:Handler是进程间进行通信的一种方式。
官方:
A Handler allows you to send and process
Message
and Runnable objects associated with a thread’sMessageQueue
. Each Handler instance is associated with a single thread and that thread’s message queue. When you create a new Handler it is bound to aLooper
. It will deliver messages and runnables to that Looper’s message queue and execute them on that Looper’s thread.Handler允许你发送Message并处理Runnable对象,通过MessageQueue的关联。每个Handler实例和线程,和线程的MessageQueue相关联。当你创建Handler的时候他会绑定到Looper。他会将message和runnables交付到Looper的message列队中,并在Looper线程中执行他(runnables)。
There are two main uses for a Handler: (1) to schedule messages and runnables to be executed at some point in the future; and (2) to enqueue an action to be performed on a different thread than your own.
主要两个作用:1.在未来某个时刻执行任务;2.在不同的线程中入队并执行相关操作。
Handler机制和原理
大致流程如图,首先初始化一个Handle(callback)
,后调用sendMsg(msg)
方法【post方法最后也是调用的sendMsg()】,传入Message对象,将这个handle赋值给msg.target。然后调用queue.enqueueMessage(msg)
将message入队。
另一方面,另外一个线程(通常为主线程)会调用Looper.loop()
方法循环从Message Queue中读取数据【此方法在ActivityThread类中已被调用,所以主线程不用再次调用;若为其他线程则需要自己手动调用一次了】。获取到数据后调用msg.target.dispatchMessage(msg);
方法。target就是handler,这里就跳回到了Handle所在线程中来,最后执行message.callback.run();
【或者handle.handleMessage()
】。
实现了线程的切换。
这里Handle和Lopper一定在一个线程,因为初始化handle之前必须要执行
Looper.prepare()
方法,【因为handle中要持有Looper对象,因为messageQueue是从Looper对象中获取到的】。之所以我们平常没写
Looper.prepare()
也能运行,是因为ActivityThread中已经调用了该方法。
Handler是怎么切换线程的
上面:point_up:已经写了。看了上文还不懂可能我表达出了问题。
Handler内存泄露的原因?
直接在MainActivity中匿名内部类 new Handle(){}
或者创建非静态内部类
的时候会有warning警告。
- 匿名内部类
- 非静态内部类:
且给出了建议,加上static,改为静态内部类。
原因是:1. 非静态内部类(或匿名内部类)【Handler
】会一直持有外部类(这里的MainActivity
)的引用。
MessageQueue
存储了Message
,而Message
的target
属性为handler
对象,handler
又持有的Activity
的对象。- 所以,当
Activiy
要销毁的时候,MessageQueue
中还存在未处理完的Message
,leaks…
怎么处理handler的内存泄露;
1.静态内部类 + 弱引用
也就是上图中Android studio 建议的方案。
同时,加上WeakReference弱引用持有Activity实例,GC回收时发现了这个弱引用对象便会将其回收,从而避免内存泄露。
详细代码参考Android 内存泄露:详解 Handler 内存泄露的原因
2 .当外部类结束生命周期时,清理Handle或Looper
- 清空Handle
1 |
|
- 结束Looper
1 |
|
Looper死循环为什么不会导致应用卡死?
Android应用程序的主线程在进入消息循环过程前,会在创建一个新binder线程。
1 | public static void main(String[] args) { |
app一直开着,Looper.loop就会一直循环【就是为了保障app的运行啊】,由于有Binder线程的存在,所以Looper中会收到Message,当收到不同的Message时就会采取不同的措施:
包括所谓BIND_APPLICATION、LAUNCH_ACTIVITY等一系列方法,都是写在这里,通过接收到的消息不同,进行相应的操作。
附上Activity创建流程图一张:
参考 :
知乎:https://www.zhihu.com/question/34652589
简书:Android 内存泄露:详解 Handler 内存泄露的原因
简书:Activity启动流程