文章目录
- 一、Message 消息
- 二、ThreadLocal 线程本地变量
- 三、Looper 中的消息队列 MessageQueue
一、Message 消息
模仿 Android 中的 Message 基本功能 , 提供 what 与 obj 变量 , 提供一个回收方法 ;
此外 , 还要指明下一个消息 , 以及是哪个 Handler 发送的该消息 ;
代码语言:javascript复制package kim.hsl.handler;
public class Message {
/**
* 消息识别码
*/
int what;
/**
* 消息对象
*/
Object obj;
/**
* 指向下一个消息
*/
Message next;
/**
* 该 Message 使用哪个 Handler 进行发送的
*/
Handler target;
/**
* 回收方法
*/
public void recyle(){
obj = null;
next = null;
target = null;
}
}
二、ThreadLocal 线程本地变量
ThreadLocal 作用是 保存线程私有变量 ;
使用 ThreadLocal 维护一个变量时 , 每个使用该 ThreadLocal 线程本地变量 的线程 , 都会 被分配一个独立的变量副本 ,
每个线程 只 可以 改变本线程内的 变量副本 , 即 ThreadLocal 线程本地变量 ;
1 . ThreadLocal 定义 :
代码语言:javascript复制 /**
* 一个线程只能有一个 Looper
* 使用 ThreadLocal 来保存该 Looper
* 该变量是线程内部存储类 , 只能本线程才可以得到存储的数据 ;
*/
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<>();
2 . ThreadLocal 变量获取 : 调用 ThreadLocal 变量的 get() 方法 , 可以获取该 ThreadLocal 线程本地变量 ;
在 ThreadLocalMap map = getMap(t) 中 , 获取的 ThreadLocalMap 与 Java 中的 Map 集合没有任何关联 , 该类就是为了保存 线程本地变量而在 ThreadLocal 中设置的内部类 ; 在该 ThreadLocalMap 内部类中 , 通过 key 键 , 获取对应 value 值 ;
代码语言:javascript复制public class ThreadLocal<T> {
/**
* 返回 该线程本地变量的 当前线程的变量副本.
* 如果 该线程中对应的 变量没有值, 应该首先初始化该变量值
*
* @return 返回当前线程的线程本地变量值
*/
public T get() {
// 首先通过 Thread 拿到当前的线程
Thread t = Thread.currentThread();
// 通过当前线程 , 获取当前线程的 ThreadLocalMap
ThreadLocalMap map = getMap(t);
if (map != null) {
// 通过 key 获取指定的 value
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
}
3 . ThreadLocal 变量设置 : 调用 ThreadLocal 的 put() 方法 , 可以设置 线程本地变量 ;
4 . Looper 中关于 线程本地变量 的设置 : 在 Looper 中涉及到了 线程本地变量 的设置 ,
Looper 要求每个线程只能保持一个 , 并且各个线程之间的 Looper 相互独立 , 没有任何关联 ;
这就需要 将 Looper 定义成线程本地变量 ;
代码语言:javascript复制public class Looper {
/**
* 一个线程只能有一个 Looper
* 使用 ThreadLocal 来保存该 Looper
* 是线程内部存储类 , 只能本线程才可以得到存储的数据 ;
*/
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<>();
/**
* 准备 Looper 方法
* 其中
* 使用了 sThreadLocal.get() 获取线程本地变量
* 使用了 sThreadLocal.set(new Looper()) 设置线程本地变量
*/
public static void prepare(){
// 先进行判断 , 如果当前线程已经有了 Looper , 那就抛出异常
if(sThreadLocal.get() != null){
throw new RuntimeException("当前线程已存在 Looper");
}
// 如果不存在 Looper , 就创建一个 Looper
sThreadLocal.set(new Looper());
}
三、Looper 中的消息队列 MessageQueue
在 Looper 中首先要维护一个 ThreadLocal 线程本地变量 , 确保每个线程中都可以获取到一个该变量的独立副本 ;
维护消息队列 : 每个 Looper 中还要维护一个 MessageQueue 消息队列 , 用于存储从 Handler 中发送来的消息 ;
该消息队列 在 Looper 初始化时创建 ;
代码语言:javascript复制package kim.hsl.handler;
public class Looper {
/**
* 一个线程只能有一个 Looper
* 使用 ThreadLocal 来保存该 Looper
* 是线程内部存储类 , 只能本线程才可以得到存储的数据 ;
*/
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<>();
/**
* 消息队列
*/
public MessageQueue mQueue;
/**
* Looper 构造函数
*/
private Looper(){
mQueue = new MessageQueue();
}
/**
* 获取当前线程对应的 Looper
* @return
*/
public static Looper looper(){
return sThreadLocal.get();
}
/**
* 准备 Looper 方法
*/
public static void prepare(){
// 先进行判断 , 如果当前线程已经有了 Looper , 那就抛出异常
if(sThreadLocal.get() != null){
throw new RuntimeException("当前线程已存在 Looper");
}
// 如果不存在 Looper , 就创建一个 Looper
sThreadLocal.set(new Looper());
}
}