1. 消息机制
1.1 post
系列
通过查看源码可知,post(Runnable r)
、postDelayed(Runnable r, long delayMillis)
最终调用的都是sendMessageDelayed
方法:
// post
public final boolean post(Runnable r){
return sendMessageDelayed(getPostMessage(r), 0);
}
// postDelayed
public final boolean postDelayed(Runnable r, long delayMillis){
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
1.2 postAtTime
postAtTime(Runnable r, long uptimeMillis)
最终调用的是sendMessageAtTime
方法:
// postAtTime
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis){
return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}
这里面都有一个共同的方法getPostMessage
:
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
m.callback = r
这句可以看出:getPostMessage
就是把传入的 Runnable 赋值给 Message 对象的 callback 属性。
1.3 sendEmptyMessage
sendEmptyMessage
最终指向sendEmptyMessageDelayed
函数:
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
msg.what = what
这句可以看出:sendEmptyMessageDelayed
就是把 what 赋值给 Message 的 what 属性。
1.4 sendMessage(msg : Message)
至于常用的sendMessage(msg : Message)
就不用细说了,这是直接传入 Message 类型的参数。
综合以上这几点来说,各种发送消息的方法最终都是把消息赋值给 Message 对象(或者 Message 的属性),而且这些方法最终调用的都是 MessageQueue 中的
enqueueMessage
方法,就是把消息加入消息队列
1.5 enqueueMessage
方法
方法较长,我们看看关键的几行:
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
用一个无限循环将消息加入到消息队列中(链表的形式),到这里把消息发出去并加入队列这两步算是完成了,接下来就是取出并处理消息。
1.6 Looper 取出消息
Looper 中有一个死循环(Looper.loop()
)用来不断从队列中取出消息:
public static void loop() {
final Looper me = myLooper();
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next();
...代码省略
msg.target.dispatchMessage(msg);
...代码省略
msg.recycleUnchecked();
}
}
queue.next()
每次取出一条 Message 消息,然后交由msg.targer.dispatchMessage(msg)
处理,从上篇文章中可以知道,msg.targer
就是发出消息的 Handler,所以我们只需要关注dispatchMessage(msg)
。
1.7 dispatchMessage(msg)
处理消息
dispatchMessage(msg)
在 Handler 类中
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
- msg 的 callback 不为空,调用
handleCallback
方法(message.callback.run()) - mCallback 不为空,调用
mCallback.handleMessage(msg)
- 最后如果其他都为空,执行 Handler 自身的
handleMessage(msg)
方法
第 1 点就是上面的 【1.1
post
系列】 和 【1.2postAtTime
】,第 3 点就是我们最常见的handleMessage
方法。需要注意一下就是callback.run()
这里直接调用线程的 run 方法,相当于普通方法调用,不会开启新的线程。
现在谈谈第 2 点,Handler 有很多种构造方法,除了上一篇文章提到的public Handler(Looper looper)
和Handler()
等,还有一个:
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
Callback 是这样的:
public interface Callback {
public boolean handleMessage(Message msg);
}
需要重写handleMessage
,这不就是 Handler 里面的handleMessage
吗?其实两者是有区别的:
// Handler
public void handleMessage(Message msg) {}
// Callback
public boolean handleMessage(Message msg);
Callback 里面的handleMessage
返回值是 Boolean 类型的,那么接下来分别返回 true 和 false 看看效果吧:
class MainActivity : AppCompatActivity() {
var handler: Handler? = null
var looper: Looper? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
looper = Looper.getMainLooper()
val callback = object: Handler.Callback{
override fun handleMessage(msg: Message?): Boolean {
Log.e("abc","--- Callback:threadName ---" + Thread.currentThread().name
)
return true
}
}
val thread = object : Thread() {
override fun run() {
super.run()
handler = object : Handler(looper, callback) {
override fun handleMessage(msg: Message?) {
super.handleMessage(msg)
Log.e("abc","--- handleMessage:threadName ---" + Thread.currentThread().name
)
}
}
}
}
thread.start()
myBtn.setOnClickListener {
handler?.sendEmptyMessage(4)
}
}
}
// Log 打印情况
--- Callback:threadName ---main
如果返回值类型改成 false:
val callback = object: Handler.Callback{
override fun handleMessage(msg: Message?): Boolean {
Log.e("abc", "--- Callback:threadName ---" + Thread.currentThread().name
)
return false
}
}
// Log 打印情况
--- Callback:threadName ---main
--- handleMessage:threadName ---main
所以,Callback 中的handleMessage
返回 true 就不继续执行 Handler 中的handlerMessage
了,反之则两个handleMessage
都执行。其实这些从dispatchMessage
方法中可以看出来(返回 true 则 return 终止,否则继续执行 handleMessage):
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
总结
上面主要讲了消息的发送和取出,大概知道了 Handler 消息机制的工作流程:
- Handler 对象通过
post
(postDelayed
、postAtTime
)或者sendMessage
(sendEmptyMessage
)把消息(Message)交给 MessageQueue MessageQueue.enqueueMessage
方法将 Message 以链表的形式放入消息队列中Looper.loop()
循环调用 MessageQueue 的next()
取出消息,交给 Handler 的dispatchMessage
方法处理消息dispatchMessage()
中分别判断msg.callback
和构造函数传入的mCallback
是否为空,不为空则执行它们的回调,为空则执行 Handler 自身的handlerMessage
方法。
2. Handler 内存泄漏问题
2.1 引起内存泄漏的原因
下面这样写会有内存泄漏风险:
val mHandler = object : Handler() {
override fun handleMessage(msg: Message?) {
super.handleMessage(msg)
}
}
Android Studio 会标黄警告,鼠标放在 handler 代码块部分还会弹出提示,大概意思就是建议你用静态模式或者弱引用。上面这种写法相当于定义了一个匿名内部类,非静态的匿名内部类默认是持有外部类(对应 Activity 等)引用的。如果发消息的 handler 所在线程还在执行,当前 Activity 就被 finish 了,那么该 Handler 的匿名内部类持有 Activity 的引用,所以 Activity 对象是无法被 GC 机制回收的。即:执行了 finish 代码,但 Activity 对象还在内存中(内存泄漏)。这种对象如果越来越多,就会有 OOM(内存溢出)的可能。
2.2 解决办法
kotlin 中没有静态类这个概念,这里用 java 静态内部类举例:
static class MyHandler extends Handler {
WeakReference<MyActivity> weakActivity;
MyHandler(MyActivity activity) {
weakActivity = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
MyActivity activity = weakActivity.get();
// activity.text = "......"
}
}
静态内部类不持有外部类引用,所以不会导致 Activity 对象泄漏(java 中 「静态的」等于「类的」,静态内部类如果能持有外部类引用,那说明外部类的引用就是内部「类的」,这不符合逻辑,这样写编译都不通过)。
但该静态内部类必须使用外部类的引用(比如操作 UI),此时就可以用弱引用的方式。上面代码用的是把 Activity 的弱引用在 Handler 构造函数中初始化,这样如果需要操作 UI,可以使用
activity.text = "test"
这种方式。
参考文章: