前言
Handler 是Android官方提供的一套用于UI更新的消息处理机制
。
主要功能为:发送消息
、处理消息
。
1 原理分析
我们从子线程发送消息,主线程更新UI的场景开始分析
// 子线程发消息
Message message = Message.obtain();
message.what = 0;
message.obj = ""; // something
handler.sendMessage(message);
// 主线程接收消息,更新UI
private final Handler myHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(@NonNull Message msg) {
if (msg.what == 0) {
// do something
}
return true;
}
});
复制代码
从 handler.sendMessage(message)
出发,我们找到消息发出去前的几个处理。
- 消息放入消息队列前的预处理
- 消息进入消息队列
消息放入消息队列前的预处理
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
复制代码
预处理:拿到消息队列mQueue
,然后把消息msg
,放进去。
mQueue跟进去是Looper类创建的MessageQueue
对象,里面的消息缓存架构可以了解一下。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed); // 创建消息队列
mThread = Thread.currentThread();
}
复制代码
消息进入消息队列
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this; // “抓住”当前发送消息的Handler对象
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis); // 进入消息队列
}
复制代码
注意:这里有行代码
msg.target = this;
this代表当前handler对象,也就是myHandler。
所以,发出去的消息会携带,当前handler对象的引用!
消息发出去后,Handler会进行处理messageQueue
// Looper.java
// 无限循环
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
try {
msg.target.dispatchMessage(msg);
...
} catch (Exception exception) {
...
} finally {
...
}
...
}
复制代码
可以看到looper启用了一个无限循环,不断去消息队列中找消息,然后,通过“target”调用dispatchMessage
方法,传递消息。
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
// mCallback.handleMessage(msg)
// 这也是Java多态的巧妙应用
// 主线程接收消息,更新UI
private final Handler myHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(@NonNull Message msg) {
// 主线程接收到msg
if (msg.what == 0) {
// do something
}
return true;
}
});
复制代码
2 内存泄露问题
handler的内存泄露也是老生常谈的问题,比如下面这个handler就造成了内存泄露。
private final Handler myHandler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
}
};
复制代码
原因就是这是个静态内部类,而发出去的msg,又携带着myHandler的引用,myHandler又持有对外面的Activity的匿名引用。
所以,在用户退出当前Activity时,handler内部的一些耗时操作如果还在运行,会导致activity还被handler引用,最终导致activity还存留在堆栈中,没有被回收,内存泄露。
解决内存泄露的方式也很简单,不使用这种静态内部类就行。
可以使用Handler.Callback接口的方式,也可以使用弱引用的方式。
private static class MyHandler extends Handler {
// 弱引用
private final WeakReference<Activity> mActivity;
public MyHandler(Activity mActivity) {
this.mActivity = new WeakReference<Activity>(mActivity);
}
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
Activity activity = mActivity.get();
if (activity != null) {
// do something
}
}
}
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END