5.4.1 Looper类分析
最后更新于:2022-04-02 05:50:03
我们以Looper使用的一个常见例子来分析Looper类。
**例子1**
~~~
//定义一个LooperThread
class LooperThread extends Thread {
publicHandler mHandler;
public void run() {
//① 调用prepare
Looper.prepare();
......
//② 进入消息循环
Looper.loop();
}
}
//应用程序使用LooperThread
{
......
newLooperThread().start();//启动新线程,线程函数是run
}
~~~
上面的代码一共有两个关键调用,我们对其逐一进行分析。
1. 准备好了吗?
第一个调用函数是Looper的prepare函数。它会做什么工作呢?其代码如下所示:
**Looper.java**
~~~
publicstatic final void prepare() {
//一个Looper只能调用一次prepare
if(sThreadLocal.get() != null) {
thrownew RuntimeException("Only one Looper may be created per thread");
}
//构造一个Looper对象,设置到调用线程的局部变量中
sThreadLocal.set(newLooper());
}
//sThreadLocal定义
private static final ThreadLocal sThreadLocal =new ThreadLocal();
~~~
ThreadLocal是Java中的线程局部变量类,全名应该是Thread Local Variable。我觉得,它的实现和操作系统提供的线程本地存储(TLS)有关系。总之,该类有两个关键函数:
- set:设置调用线程的局部变量。
- get:获取调用线程的局部变量。
* * * * *
**注意**,set/get的结果都和调用这个函数的线程有关。ThreadLocal类可参考JDK API文档或Android API文档。
* * * * *
根据上面的分析可知,prepare会在调用线程的局部变量中设置一个Looper对象。这个调用线程就是LooperThread的run线程。先看看Looper对象的构造,其代码如下所示:
**Looper.java**
~~~
private Looper(){
//构造一个消息队列
mQueue =new MessageQueue();
mRun =true;
//得到当前线程的Thread对象
mThread =Thread.currentThread();
}
~~~
prepare函数很简单,它主要干了一件事:
- 在调用prepare的线程中,设置了一个Looper对象,这个Looper对象就保存在这个调用线程的TLV中。而Looper对象内部封装了一个消息队列。
也就是说,prepare函数通过ThreadLocal机制,巧妙地把Looper和调用线程关联在一起了。要了解这样做的目的是什么,需要再看第二个重要函数。
2. Looper循环
代码如下所示:
**Looper.java**
~~~
public static final void loop() {
Looper me = myLooper();//myLooper返回保存在调用线程TLV中的Looper对象
//取出这个Looper的消息队列
MessageQueue queue = me.mQueue;
while (true) {
Message msg = queue.next();
//处理消息,Message对象中有一个target,它是Handler类型
//如果target为空,则表示需要退出消息循环
if (msg != null) {
if (msg.target == null) {
return;
}
//调用该消息的Handler,交给它的dispatchMessage函数处理
msg.target.dispatchMessage(msg);
msg.recycle();
}
}
}
//myLooper函数返回调用线程的线程局部变量,也就是存储在其中的Looper对象
public static final Looper myLooper() {
return (Looper)sThreadLocal.get();
}
~~~
通过上面的分析会发现,Looper的作用是:
- Looper封装了一个消息队列。
- Looper的prepare函数把这个Looper和调用prepare的线程(也就是最终的处理线程)绑定在一起了。
- 处理线程调用loop函数,处理来自该消息队列的消息。
当事件源向这个Looper发送消息的时候,其实是把消息加到这个Looper的消息队列里了。那么,该消息就将由和Looper绑定的处理线程来处理。那么,事件源又是怎么向Looper消息队列添加消息的呢?来看下一节。
3. Looper、Message和Handler的关系
Looper、Message和Handler之间也存在暧昧关系,不过要比RefBase那三个简单得多,用两句话就可以说清楚:
- Looper中有一个Message队列,里边存储的是一个个待处理的Message。
- Message中有一个Handler,这个Handler是用来处理Message的。
其中,Handler类封装了很多琐碎的工作。先来认识一下这个Handler。
';