Handler说明:
Android开发中可以使用Handler发送消息进行线程间的通信。Handler发送并处理与一个线程相关联的Message 和Runnable 【注:Runnable 会被封装进一个 Message,所以它本质上还是一个 Message】
每个 Handler 都会跟一个线程绑定,并与该线程的 MessageQueue 关联在一起,从而实现消息的管理以及线程间通信。
Handler 的基本用法:
android.os.Handler handler = new Handler() {
@Override
public void handleMessage(final Message msg) {
// 这里接受并处理消息
}
};
// 发送消息
handler.sendMessage(message);
handler.post(runnable);
Handler 原理解析:
1.Handler 是如何与线程关联的?
2.Handler 发出去的消息是谁管理的?
3.消息又是怎么回到 handleMessage() 方法的?
4.线程的切换是怎么回事?
(1)Handler 与 Looper 的关联:
我们在实例化 Handler 的时候 Handler 会去检查当前线程的 Looper 是否存在,如果不存在则会报异常,也就是说在创建 Handler 之前一定需要先创建 Looper 。
public Handler(Callback callback,boolean async) {
//检查当前的线程是否有 Looper
mLooper= Looper.myLooper();
if (mLooper== null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
//Looper 持有一个 MessageQueue
mQueue= mLooper.mQueue;
}
一个完整的 Handler 使用例子:
class LooperThread extends Thread {
public HandlermHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
Looper.prepare() :
//Looper
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get()!= null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
Looper 提供了Looper.prepare()方法来创建 Looper ,并且会借助 ThreadLocal 来实现与当前线程的绑定功能。Looper.loop() 则会开始不断尝试从 MessageQueue 中获取 Message , 并分发给对应的 Handler。
也就是说 Handler 跟线程的关联是靠 Looper 来实现的。
(2)Message 的存储与管理
Handler 提供了一些列的方法让我们来发送消息,如 send()系列 post()系列 。
不过不管我们调用什么方法,最终都会走到Message.enqueueMessage(Message,long)方法。
以sendEmptyMessage(int)方法为例:
//Handler
sendEmptyMessage(int)
->sendEmptyMessageDelayed(int,int)
->sendMessageAtTime(Message,long)
->enqueueMessage(MessageQueue,Message,long)
-> queue.enqueueMessage(Message,long);
消息的管理者 MessageQueue负责message消息的存放与管理,MessageQueue 就是个消息队列,负责消息的入队出队。
(3)Message 的分发与处理
Looper.loop() 负责对消息的分发
//Looper
public static void loop() {
final Looperme = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueuequeue = me.mQueue;
//...
for (;;) {
// 不断从 MessageQueue 获取 消息
Messagemsg = queue.next();// might block
//退出 Looper
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
//...
try {
msg.target.dispatchMessage(msg);
end= (slowDispatchThresholdMs== 0)? 0 : SystemClock.uptimeMillis();
}finally {
//...
}
//...
//回收 message
msg.recycleUnchecked();
}
}
loop() 里调用了 MessageQueue.next() ,还调用了 msg.target.dispatchMessage(msg) ,msg.target 就是发送该消息的 Handler,这样就回调到了 Handler 那边去了:
//Handler
public void dispatchMessage(Message msg) {
//msg.callback 是 Runnable ,如果是 post方法则会走这个 if
if (msg.callback!= null) {
handleCallback(msg);
}else {
//callback
if (mCallback!= null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//回调到 Handler 的 handleMessage 方法
handleMessage(msg);
}
}
dispatchMessage() 方法针对 Runnable 的方法做了特殊处理,如果是 ,则会直接执行Runnable.run()。
分析:Looper.loop() 是个死循环,会不断调用 MessageQueue.next() 获取 Message ,并调用msg.target.dispatchMessage(msg)回到了 Handler 来分发消息,以此来完成消息的回调。
注意:loop()方法并不会卡死主线程。
线程的切换:
Thread.foo(){
Looper.loop()
-> MessageQueue.next()
-> Message.target.dispatchMessage()
-> Handler.handleMessage()
}
Handler.handleMessage() 所在的线程最终由调用 Looper.loop() 的线程所决定。
图示(4)小结
Looper :负责关联线程以及消息的分发在该线程下**从 MessageQueue 获取 Message,分发给 Handler ;
MessageQueue :是个队列,负责消息的存储与管理,负责管理由 Handler 发送过来的 Message。
Handler :负责发送并处理消息,面向开发者,提供 API。
Handler 发送的消息由 MessageQueue 存储管理,并由 Loopler 负责回调消息到 handleMessage()。
线程的转换由 Looper 完成,handleMessage() 所在线程由 Looper.loop() 调用者所在线程决定。
(5)常见的一些问题
1.Handler 引起的内存泄露原因以及最佳解决方案:
Handler 允许我们发送延时消息,如果在延时期间用户关闭了 Activity,那么该 Activity 会泄露。
这个泄露是因为 Message 会持有 Handler,而又因为Java 的特性,内部类会持有外部类,使得 Activity 会被 Handler 持有,这样最终就导致 Activity 泄露。
解决该问题的最有效的方法是:将 Handler 定义成静态的内部类,在内部持有 Activity 的弱引用,并及时移除所有消息。
示例代码如下:
private static class MyHandler extends Handler {
private WeakReference<HandlerActivity> ref;
public MyHandler(HandlerActivity activity) {
this.ref = new WeakReference(activity);
}
@Override
public void handleMessage(final Message msg) {
HandlerActivityactivity = ref.get();
if (activity != null) {
activity.handleMessage(msg);
}
}
}
并且再在Activity.onDestroy()前移除消息
@Override
protected void onDestroy() {
myHandler.removeCallbacksAndMessages(null);
super.onDestroy();
}
注意:单纯的在 onDestroy 移除消息并不保险,因为onDestroy 并不一定执行。
2.创建 Message 实例的最佳方式
由于 Handler 极为常用,所以为了节省开销,Android 给 Message 设计了回收机制,所以我们在使用的时候尽量复用 Message ,减少内存消耗。
方法有二:
通过 Message 的静态方法Message.obtain();获取;
通过 Handler 的公有方法handler.obtainMessage();。
网友评论