Android的消息机制主要是指Handler的运行机制。在日常开发中经常是在子线程中执行完一些耗时操作后(网络请求,I/O操作等)需要更新ui,由于不能在子线程中更新ui,这时就需要handler将更新ui的操作切换到主线程中执行。
它的主要作用是将一个任务切换到某个指定的线程中处理。
Handler的运行需要底层MessageQueue和Looper的支持。
MessageQueue 消息队列,它存储了一组消息,主要做消息插入,删除工作,但它本质是单链表结构。
Looper 消息循环。MessageQueue只是用于存储消息,它并不处理消息,Looper用于处理消息,它以无限循环的方式查找是否有新消息,如果有就处理新消息,否则就一直等待。在Looper中还有一个ThreadLocal的概念。
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
ThreadLocal可以在不同线程中互不干扰的存储并提供数据,通过ThreadLocal可以获取到每个线程的Looper.
线程中默认是没有Looper的,要使用Handler必须为线程创建Looper。
在主线程中(ActivityThread)默认可以使用Handler是因为主线程在创建时初始化了Looper.
public static void main(String[] args) { // Make sure TrustedCertificateStore looks in the right place for CA certificates final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId()); TrustedCertificateStore.setDefaultUserDirectory(configDir); Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper();//在这里,在这里 ActivityThread thread = new ActivityThread(); thread.attach(false);
Handler的工作过程
可以通过handler的post()或sendMessage()的方式将一个message投递到Handler内部的Looper中处理。
Handler handler=new Handler();
handler.post(new Runnable() {
@Override
public void run() {
//do anything you want
}
});
handler.sendMessage(new Message());
通过查看源码发现这两种方法最终都会调用下面的方法:
enqueueMessage(queue, msg, uptimeMillis);
这个方法是将新的消息插入到消息队列中。
Looper的loop方法是一个死循环,唯一跳出死循环的情况是MessageQueue.next()方法返回了null,当next()方法返回不为null时说明有新的消息到来,这时Handler的dispatchMessage()方法会被调用,也就是Runnable方法或者Handler的handleMessage方法被调用。因为Looper是运行在Handler所在的线程中,所以任务就被切换到了Handler所在的线程中。源码如下:
Looper中的loop方法:
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the 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;
}
.......
.......
.......
.......
try {
msg.target.dispatchMessage(msg);
.........
}
.........
}
}
Handler中的dispatchMessage方法:
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
Handler存在的问题:
如果Activity已经finish,但这时handler的任务可能并没有完(例如延时),这时就会出现内存泄漏。如何避免:
-
使用静态内部类创建Handler对象,并持有activity弱引用
在Java中非静态内部类会隐性地持有外部类的引用,而非静态内部类则不会。
private static class NoLeakHandler extends Handler{ private WeakReference<NoLeakActivity> mActivity; public NoLeakHandler(NoLeakActivity activity){ mActivity = new WeakReference<>(activity); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); } }
2.在activity finish时及时的清除消息
@Override
protected void onDestroy() {
super.onDestroy();
handler.removeCallbacksAndMessages(null);
}