目录
同一个Thread线程里只能有一个Looper对象。
在 Android 中,ThreadLocal 是一个非常有用的工具,它允许你在每个线程中存储和访问独立的变量副本。Looper 是 Android 的消息循环器,它在特定的线程中运行消息循环,并处理消息队列中的消息。ThreadLocal 和 Looper 的结合使得每个线程可以有一个独立的 Looper 实例。
ThreadLocal 的基本原理
ThreadLocal 提供了线程局部变量,确保每个线程都有自己的变量副本,而不会与其他线程的变量副本冲突。它的工作原理如下:
- 每个线程都有一个 ThreadLocalMap,存储 ThreadLocal 变量。
- 当线程访问 ThreadLocal 变量时,会从线程的 ThreadLocalMap 中获取对应的值。
- 如果 ThreadLocal 变量在当前线程中不存在,则会创建一个新的变量副本,并存储在 ThreadLocalMap 中。
Looper 和 ThreadLocal 的结合
在 Android 中,Looper 使用 ThreadLocal 来确保每个线程只能有一个 Looper 实例。
如何使用 ThreadLocal 的示例
1. ThreadLocal 变量的定义
在 Looper 类中,有一个静态的 ThreadLocal 变量,用于存储每个线程的 Looper 实例。
private static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
2.创建 Looper 实例
当你在一个线程中调用 Looper.prepare() 方法时,会创建一个新的 Looper 实例,并将其存储在 ThreadLocal 变量中。
public static void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
在这个方法中,首先检查当前线程是否已经有一个 Looper 实例。如果有,则抛出异常,确保每个线程只能有一个 Looper 实例。如果没有,则创建一个新的 Looper 实例,并将其存储在 ThreadLocal 变量中。
3. 获取 Looper 实例
当你需要获取当前线程的 Looper 实例时,可以调用 Looper.myLooper() 方法。
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
这个方法从 ThreadLocal 变量中获取当前线程的 Looper 实例,并返回它。
示例
完整的示例
public class LooperExample {
public static void main(String[] args) {
// 创建一个新线程,并在其中创建 Looper
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// 准备 Looper
Looper.prepare();
// 获取当前线程的 Looper
Looper looper = Looper.myLooper();
System.out.println("Looper in thread: " + looper);
// 开始消息循环
Looper.loop();
}
});
thread.start();
// 主线程中尝试获取 Looper
Looper mainLooper = Looper.myLooper();
System.out.println("Looper in main thread: " + mainLooper);
}
}
在示例中,创建了一个新线程,并在其中调用 Looper.prepare() 方法来创建一个 Looper 实例。然后,可以通过 Looper.myLooper() 方法获取当前线程的 Looper 实例。主线程中尝试获取 Looper 时,会返回 null,因为主线程中没有调用 Looper.prepare() 方法。
总结
通过使用 ThreadLocal,Looper 可以确保每个线程只能有一个 Looper 实例。这种机制不仅简化了 Looper 的管理,还确保了消息循环的正确性。每个线程都有自己的消息队列和消息循环,不会与其他线程的消息循环冲突。