一、ThreadLocal
线程局部存储(ThreadLocalStorage)当从同一线程中引用该变量时,其值总是相同;而从不同的线程中引用该变量时,其值应该不同。
作用域:
方法成员变量:仅在方法内部有效
类成员变量:仅在对象内部有效
线程局部存储(TLS)变量:在本线程内的任何对象内保持一致
静态变量:在本进程内的任何对象内保持一致
跨进程通信(IPC)变量:一般使用 Binder 定义,在所有进程中保持
二、Looper
./frameworks/base/core/java/android/os/Looper.java
作用:
1、调用该类中的静态方法 prepare() 创建一个消息队列
在 Looper 的静态方法 prepare() 中,给线程局部存储变量中添加一个新的 Looper 对象:
public static final void prepare() {if (sThreadLocal.get() != null) {throw new RuntimeException("Only one Looper may be created per thread");}sThreadLocal.set(new Looper());}
Looper 的构造方法中创建了一个 MessageQueue 对象:
private Looper() {mQueue = new MessageQueue();mRun = true;mThread = Thread.currentThread();}
2、提供静态方法 loop() ,使调用该方法的线程进行无限循环,并从消息队列中读取消息
对程序员来讲,当需要把一个线程变为异步消息处理线程时,应该在 Thread 类的 run() 方法中先调用 Looper.prepare() 为该线程创建一个 MessageQueue 对象,然后再调用 Looper.loop() 方法,使当前线程进入消息处理循环
1 public static final void loop() {
2 Looper me = myLooper();
3 MessageQueue queue = me.mQueue;
4 while (true) {
5 Message msg = queue.next(); // might block
6 //if (!me.mRun) {
7 // break;
8 //}
9
10 if (msg != null) {
11 if (msg.target == null) {
12 // No target is a magic identifier for the quit message.
13 return;
14 }
15 if (me.mLogging!= null) me.mLogging.println(
16 ">>>>> Dispatching to " + msg.target + " "
17 + msg.callback + ": " + msg.what
18 );
19
20 msg.target.dispatchMessage(msg);
21
22 if (me.mLogging!= null) me.mLogging.println(
23 "<<<<
25
26 msg.recycle();
27 }
28 }
29 }
1&#xff09;调用 myLooper() 函数返回当前线程的 Looper对象&#xff0c;调用 sThreadLocal.get() 方法返回当前线程 ID 对应的 Looper 对象
public static final Looper myLooper() {return (Looper)sThreadLocal.get();}
2&#xff09;通过 Looper 对象获取线程的消息队列
MessageQueue queue &#61; me.mQueue;
3&#xff09;进入 while 无限循环
&#xff08;1&#xff09;调用MessageQueue 对象的 next() 方法取出队列中的消息&#xff08;如果当前队列为空&#xff0c;则当前线程会被挂起&#xff0c;也就是说 next() 内部会暂停当前线程&#xff09;
Message msg &#61; queue.next();
&#xff08;2&#xff09;回调 dispatchMessage(msg) 完成对消息的处理。msg 变量的类型是 Message&#xff0c; msg.target 的类型是 Handler
msg.target.dispatchMessage(msg);
&#xff08;3&#xff09;处理完消息后&#xff0c;调用 msg.recycle() 回收 Message 对象占用的系统资源。因为 Message 类内部使用了一个数据池保存 Message 对象&#xff0c;从而避免不停的创建和删除 Message 对象&#xff0c;因此每次处理完该消息后需要将 Message 对象表明为空闲状态
三、MessageQueue
./frameworks/base/core/java/android/os/MessageQueue.java
1、消息在 MessageQueue 中以 Message 表示&#xff0c;消息以链表的结构进行保存
2、MessageQueue 中两个主要的方法“取出消息”和“添加消息”
1&#xff09;取出消息 next()
final Message next() {...// Try to retrieve the next message, returning if found.synchronized (this) {now &#61; SystemClock.uptimeMillis();Message msg &#61; pullNextLocked(now);if (msg !&#61; null) return msg;if (tryIdle && mIdleHandlers.size() > 0) {idlers &#61; mIdleHandlers.toArray();}}...}
2&#xff09;添加消息 enquenceMessage()
final boolean enqueueMessage(Message msg, long when) {...synchronized (this) {...msg.when &#61; when;//Log.d("MessageQueue", "Enqueing: " &#43; msg);Message p &#61; mMessages;if (p &#61;&#61; null || when &#61;&#61; 0 || when < p.when) {msg.next &#61; p;mMessages &#61; msg;this.notify();} else {Message prev &#61; null;while (p !&#61; null && p.when <&#61; when) {prev &#61; p;p &#61; p.next;}msg.next &#61; prev.next;prev.next &#61; msg;this.notify();}}return true;}
四、Handler
./frameworks/base/core/java/android/os/Handler.java
1、尽管 MessageQueue 提供了直接读/写的函数接口&#xff0c;但对于应用程序员而言一般不直接读/写消息队列。在Looper.loop() 函数中&#xff0c;当取出消息后回调 msg.target 的 handleMessage() 方法&#xff0c;而 msg.target 的类型正是 Handler。
public void dispatchMessage(Message msg) {if (msg.callback !&#61; null) {handleCallback(msg);} else {if (mCallback !&#61; null) {if (mCallback.handleMessage(msg)) {return;}}handleMessage(msg);}}
我们一般用 Handler 类向消息队列中发送消息&#xff0c;并重载 Handler 类的 handleMessage() 函数添加消息处理代码。
2、Handler 对象只能添加到有消息队列的线程中&#xff0c;否则发生异常
mLooper &#61; Looper.myLooper();
if (mLooper &#61;&#61; null) {throw new RuntimeException("Can&#39;t create handler inside thread that has not called Looper.prepare()");
}
因此&#xff0c;在构造 Handler 对象前必须已经执行过 Looper.prepare() &#xff0c;但 Looper.prepare() 不能被执行两次。
五、UI线程和自定义 Thread的区别
1、UI线程是从 ActivityThread 运行的&#xff0c;在 ActivityThread 中的 main() 方法中已经使用 Looper.prepareMainLooper() 为线程添加了 Looper 对象&#xff08;即已经创建了消息队列MessageQueue&#xff09;
2、自定义 Thread 是一个裸线程&#xff0c;因此不能直接在 Thread 中定义 Handler对象