【Android】Handler机制
Android线程相关
Android应用程序的main函数在ActivityThread中。程序启动后会有默认的主线程(UI线程)。
在线程中关联一个消息队列,所有操作会被封装成消息交给主线程处理。
ActivityThread的main()
:
public static void main(String[] args) {
...
looper.prepareMainLooper(); // 创建消息循环Looper
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler(); // UI线程的Handler
}
...
Looper.loop(); // 执行消息循环
...
}
Handler
每个Handler会关联消息队列,消息队列封装在Looper中,而每个Looper会关联一个线程(Looper通过ThreadLocal封装),所以每个消息队列会关联一个线程。
默认情况下,只有主线程的消息队列,通过looper.prepareMainLooper()
来创建,Looper.loop()
启动消息循环。
Handler与消息队列的关联
public Handler(@Nullable Callback callback, boolean async) {
... //内存泄漏相关
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
myLooper()
通过sThreadLocal.get()
来获取Looper对象。
在prepareMainLooper()
中调用了prepare()
,将Looper对象设置给了sThreadLocal,队列就与线程关联起来了。
所以更新的Handler必须在主线程中创建,才能跟主线程的消息队列关联上。
消息循环
Looper.loop()
方法:
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue; //获取消息队列
for (;;) { // 死循环处理消息
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
msg.target.dispatchMessage(msg); // 消息分发
...
msg.recycleUnchecked(); // 消息回收
}
}
msg的target为Handler,实际为Handler将Message投递到MessageQueue,MessageQueue又将Message分发给Handler处理。
Handler中的dispatchMessage()
:
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
如果Runnable类型的callback为空,则执行handlMessage()
方法来处理消息;如果不为空,则执行handleCallback()
来处理。这分别为Handler的两种分发方式。所以有以下的两种使用方式:
- 使用
post(Runnalble callback)
来发送消息,这时执行handleCallback方式 - 使用
sendMessage(Message msg)
来发送消息,这时执行handleMessage方式
在子线程中创建Handler
子线程中默认Looper为空,所以之间创建Handler会报错,所以需要先prepare()
为该线程创建Looper,然后loop()
启动消息循环。
new Thread() {
Handler handler = null;
public void run() {
Looper.prepare();
handler = new Handler();
Looper.loop();
}.start();
}
Handler内存泄漏问题
https://juejin.im/post/5ccaa95ae51d453b222b7953
当Handler定义为非静态内部类或者匿名内部类,使得Handler默认持有外部类的引用。Activity销毁时,由于Handler可能有未执行完或正在执行的Message,由于Handler持有Activity的引用,使得GC无法回收Activity。
匿名内部类:
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage
}
}
非静态内部类:
protected class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
...
}
}
解决方法:
-
在销毁时清空Handler中所有的消息和callback
@Override protected void onDestroy() { super.onDestroy(); mHandler.removeCallbackAndMessage(null); }
-
静态内部类+弱引用
private static class MyHandler extends Handler { WeakReference<Activity> activity; MyHandler(Activity activity) { this.activity = new WeakReference<Activity>(activity); } ... }