相关推荐:
- Android 源码阅读 | Handler
- Android 源码阅读 | Looper
- Android 源码阅读 | MessageQueue
- Android 源码阅读 | Message
- Android 自定义 View | 扭曲动效
类注释
Class used to run a message loop for a thread. Threads by default do
not have a message loop associated with them; to create one, call
{@link #prepare} in the thread that is to run the loop, and then
{@link #loop} to have it process messages until the loop is stopped.
<p>Most interaction with a message loop is through the
{@link Handler} class.
- Looper类通常用户为线程提供消息循环。
- 线程默认下不会有消息循环,为了创建它,在线程里面调用 Looper.prepare ,接着调用 Looper.loop ,进行处理消息,直到循环停止。
- 大多数与消息循环的交互都是通过 Handler 类进行的。
* <p>This is a typical example of the implementation of a Looper thread,
* using the separation of {@link #prepare} and {@link #loop} to create an
* initial Handler to communicate with the Looper.
*
* <pre>
* class LooperThread extends Thread {
* public Handler mHandler;
*
* public void run() {
* Looper.prepare();
*
* mHandler = new Handler() {
* public void handleMessage(Message msg) {
* // process incoming messages here
* }
* };
*
* Looper.loop();
* }
* }</pre>
在类注释里面,有一个使用 Looper 的例子,其核心是调用两个方法:Looper.prepare(); 和 Looper.loop();
prepare() & loop()
prepare()
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
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));
}
在prepare方法中,对 ThreadLocal进行初始化,我们知道,ThreadLocal用于保存某个线程共享变量:对于同一个static ThreadLocal,不同线程只能从中get,set,remove自己的变量,而不会影响其他线程的变量。就是说,不同线程中,此处的 sThreadLocal 会是一个不同的变量。
而,prepare 方法还限制了,一个线程中只能有一个 looper。
loop()
public static void loop() {
final Looper me = myLooper();
//省略...
for (;;) {
Message msg = queue.next(); // might block
//省略...
// 1. msg.target,其实就是 handler 对象,调用分发方法
try {
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
//省略...
// 2. 分发完成后,直接 recycle 回收 messageBean
msg.recycleUnchecked();
}
}
- loop 调用后,进入一个for循环,无限循环
- 在 Message msg = queue.next(); 阻塞当前线程,直到获取到一个需要处理的消息 msg 。
- 获取到待处理消息后,执行 msg.target.dispatchMessage(msg); 把消息分发到对应的handler上,回调 handler 的 handleMessage 方法,完成对消息的处理
- 最后,回收消息 msg.recycleUnchecked();
构造方法
final MessageQueue mQueue;
final Thread mThread;
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
私有化构造函数,并且保留当前的线程引用和初始化一个 MessageQueue 消息队列。
prepareMainLooper()
private static Looper sMainLooper; // guarded by Looper.class
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. The main looper for your application
* is created by the Android environment, so you should never need
* to call this function yourself. See also: {@link #prepare()}
*/
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
定义了一个 sMainLooper ,这就是主线程的Looper,和上面子线程的looper是一样的初始化逻辑。
其他
quit方法是结束队列的循环,调用的是 mQueue 里面的方法,可以看 MessageQueue 里面的源码分析。
public void quit() {
mQueue.quit(false);
}
public void quitSafely() {
mQueue.quit(true);
}
总结
- Looper是循环者,带动着整个MessageQueue进行循环
- 通过ThreadLocal巧妙地让每一个字线程拥有自己唯一的Looper
- Looper结束队列循环需要调用quit方法,quit方法会直接丢弃未到合适时间处理的消息。
码字不易,方便的话素质三连,或者关注我的公众号 技术酱,专注 Android 技术,不定时推送新鲜文章,如果你有好的文章想和大家分享,欢迎关注投稿!