Looper类和Handler类分析
工作原理
- 有一个消息队列,可以往这个消息队列中投递消息
- 有一个消息循环,不断从消息队列中取出消息,然后处理.
- 事件源添加待处理的消息,一般是在队尾添加如果有优先级高的消息,按照优先级越高位置越靠前.
- 事件源提交消息:通过 按键,触屏 等物理时间产生,也可以是 系统或应用 本身发出的请求
Looper类
class LooperThread extends Thread{
@Override
public void run() {
super.run();
//调用prepare
Looper.prepare();
//进入消息循环
Looper.loop();
}
}
关键两步(1)Looper.prepare();
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));
}
prdepare函数主要做一个事情
在调用prepare的线程中,设置了一个Looper对象,这个Looper对象保存在这个调用线程的TLV中,Looper对象内部封装了一个消息队列
也就是说,prepare函数通过ThreadLocal机制,巧妙的把Looper和调用线程关联在一起.
(2)Looper.loop();
public static void loop() {
//关键代码
final Looper me = myLooper();
mThread = Thread.currentThread();
}
Looper的作用是:
1.封装了一个消息队列
2. Looper的prepare函数把这个Looper和调用prepare的线程(最终的处理线程)绑定在一个.
3. 处理线程调用了loop函数,处理来自该消息队列的消息.
[总结]
Looper有一个Message队列,里边储存的是一个个待处理的message
Message中有一个Handler,这个Handler是用来处理Message的
Handler分析
包含成员
- MessageQueue
- Looper
- Callback
在不使用Handler的情况下,插入消息需要:
1. 调用Looper的myQueue,它返回一个MessgeQueue
2. 构造一个Message 填充它的成员,尤其是target变量.
3. 调用mesaageQueue的enqueueMessage,将消息插入队列
这种原始方法很麻烦,也容易出错,下面看看有了Handler以后我们的工作得到了那些优化:
//查看队列中是否有消息
public final boolean hasMessages(int what)
//从handler中创建一个消息
public final Message obtainMessage()
//从消息队列中移除消息
public final void removeCallbacks(Runnable r)
//发送一个消息,该消息添加到队列头--优先级最高
public final boolean sendEmptyMessageAtTime
.
.
.
Handler 把Message的target设置为自己,因为Handler除了封装消息添加等功能外,还封装了消息处理的接口.
Looper 在获得消息后会调用target.dispatchMessage函数,再把这个消息派发给Handler处理.
- dispatchMessage 定义了一套消息处理的优先级机制如下:
- Message自带了callback 处理,则交给callback处理
- Handler如果设置了全局的mCallback,则交给callback处理.
- 如果上述都没有,该消息则会被交给Handler子类实现的handleMessage来主城里(需要Handler培生并重载handleMessage函数)
通常情况下,我们一旦都是采用第三种方法–在子类中通过重载handleMessage来完成处理工作.
拓展
HandlerThread
测试场景
主线程有耗时操作,同时需要handlemessage接受一些更新操作,这是需要再开启一个线程
//开启子线程2
handlerThread = new HandlerThread("handler_Thread");
//运行子线程
handlerThread.start();
/**
*子线程与handler 进行关联 注:此处getLooper不可以使用Looper.getLooper(获取当前线程的looper即主线程looper)
**/
handler = new Handler(handlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.e("handler=====", msg.getTarget().getLooper().getThread().getName());
handlerMain.sendEmptyMessage(1);
}
};
//主线程
handlerMain = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.e("handler=====", msg.getTarget().getLooper().getThread().getName());
handlerThread.quit();
handler.removeCallbacksAndMessages(null);
}
};
//UI耗时操作
private void initUI() {
runOnUiThread(new Runnable() {
@Override
public void run() {
try {
handler.sendEmptyMessage(1);
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
运行结果: handler_Thread 立即触发
main 被阻塞延时5秒
- [参考文献] 深入理解Android卷I