1, 基本概念
Handler主要做什么?机制是怎样的?有其他相同或者类似的机制吗?
我们知道,Binder主要用于跨进程通信,Handler呢?主要用于进程内部进行通信,或者说进程内部不同线程之间进行通信,即是不同线程之间互相发送消息。
额外知识:
libcore/libart/src/main/java/java/lang/Thread.java
libcore/luni/src/main/java/java/lang/ThreadLocal.java
Thread类的内容有一个成员专门用于存储线程的ThreadLocal的数据。
ThreadLocal是做啥的呢? 啥都不说,直接上例子:
1. private ThreadLocalmBooleanThreadLocal = newThreadLocal(Boolean);
2.
3. mBooleanThreadLocal.set(true);
4. Log.d(TAG, [Thread#main]mBooleanThreadLocal=+ mBooleanThreadLocal.get());
5.
6. new Thread(Thread#1) {
7. @Override
8. publicvoid run() {
9. mBooleanThreadLocal.set(false);
10. Log.d(TAG,[Thread#1]mBooleanThreadLocal= + mBooleanThreadLocal.get());
11. };
12. }.start();
13.
14. new Thread(Thread#2) {
15. @Override
16. publicvoid run() {
17. Log.d(TAG,[Thread#2]mBooleanThreadLocal= + mBooleanThreadLocal.get());
18. };
19. }.start();
20.
输出结果:
21. D/TestActivity(8676):[Thread#main]mBooleanThreadLocal=true
22. D/TestActivity(8676):[Thread#1]mBooleanThreadLocal=false
23. D/TestActivity(8676):[Thread#2]mBooleanThreadLocal=null
很神奇吧,可以这样理解, ThreadLocal虽然作为主线程的全部变量,但是在不同的字线程中都有各自一个独立的副本,彼此之间互不干扰。也就是说ThreadLocal是基于线程的。
那么Handler相关消息概念中为啥要使用ThreadLocal呢?
对于Handler来说,它需要获取当前线程的Looper,通过ThreadLocal就可以轻松实现Looper在线程中的存取.如果不采用ThreadLocal,那么系统就必须提供一个全局的哈希表供Handler查找指定线程的Looper,这样一来就必须提供一个类似于LooperManager的类了,这就是ThreadLocal的好处。
所以, 当某些数据是以线程为作用域并且不同线程具有不同的数据副本的时候,就可以考虑采用ThreadLocal。比如比如Looper、ActivityThread以及AMS等都用到了ThreadLocal。
主要做两件事情,1,(延时)发送消息;2,(延时)运行一个线程,最后都是以消息的形式封装处理。
主要包括三个类:handler, Looper, MessageQueue,还有Message
消息的表示:Message
消息队列:MessageQueue
消息循环,用于循环取出消息进行处理:Looper
消息处理,消息循环从消息队列中取出消息后要对消息进行处理:Handler
一个进程仅有一个looper,looper中包含一个消息链表(按照时间排序).
同一个handler可以对应(处理)不同的消息(Message)
2, 流程图
在apk启动时,会创建一个主线程,在ActivityThread的main函数中
【frameworks/base/core/java/android/app/ActivityThread.java】
1. public static void main(String[] args) {
2. ···
3. Looper.prepareMainLooper();
4. ···
5. Looper.loop();
6. }
流程如下:
2.1 Looper初始化
7. private static void prepare(booleanquitAllowed) {
8. ···
9. sThreadLocal.set(newLooper(quitAllowed));
10. // 构造当前线程的Looper并且保存在sThreadLocal中
11. }
12. private Looper(boolean quitAllowed) {
13. mQueue = new MessageQueue(quitAllowed);//构造消息队列 MessageQueue
14. mThread = Thread.currentThread();
15. }
16. MessageQueue(boolean quitAllowed) {
17. mQuitAllowed = quitAllowed;
18. mPtr = nativeInit();// 该函数是一个C/C++层函数
19. }
可以看看mQuitAllowed的定义:
20. // True if the message queue can be quit.
21. private final boolean mQuitAllowed;
该变量为false时表示不可以退出,只有主线程在调用prepare函数时传入false。也就是说仅有主线程不允许退出。
2.2 获取当前线程的Looper
直接看myLooper函数: