初级篇
Looper代码位于下面的位置,只有279行。
Frameworks/base/core/java/android/os/Looper.java 279行
Looper负责线程消息分发。
Prepare()进行初始化,loop()进入消息分发循环,quit()结束消息分发。
看一下构造方法
Looper实例化的时候会创建MessageQueue()对象,并绑定自己到当前线程上。
下面看一下Looper类的最重要的方法loop()
先拿到消息队列的对象,然后进入无限循环。通过MessageQueue的next()方法取得要处理的Message,如果为null,表示消息队列已经结束了;否则发送消息给对应的Handler处理。最后回收消息到消息池。
另外,主线程(main线程/UI线程)不需要开发者调用Looper操作。主线程由Android系统创建,在创建的时候系统已经进行了相应的调用。
ThreadLocal
ThreadLocal代表一个线程的局部变量,每个线程都只能看到自己的值,并不会意识到其它线程中也存在该变量。它采用空间来换取时间的方式,解决多线程中相同变量的访问冲突问题。
ThreadLocal不是Thread,是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,存储的数据只有在线程中在可以获取到,对于其它线程来说是无法获取到数据的。
使用场景一:对于 ThreadLocal 的使用场景,一般来说,当某些数据是以线程为作用域并且不同线程具有不同的数据副本的时候,就可以考虑采用ThreadLocal。比如对于Handler来说,它需要获取当前线程的Looper,很显然Looper的作用域就是线程并且不同线程具有不同的Looper,这个时候通过ThreadLocal就可以轻松实现Looper在线程中的存取,如果不采用ThreadLocal,那么系统就必须提供一个全局的哈希表供Handler查找指定线程的Looper,这样一来就必须提供一个类似于LooperManager的类了,但是系统并没有这么做而是选择了ThreadLocal,这就是ThreadLocal的好处。
使用场景二:ThreadLocal另一个使用场景是复杂逻辑下的对象传递,比如监听器的传递,有些时候一个线程中的任务过于复杂,这可能表现为函数调用栈比较深以及代码入口的多样性,在这种情况下,我们又需要监听器能够贯穿整个线程的执行过程,这个时候可以怎么做呢?其实就可以采用ThreadLocal,采用ThreadLocal可以让监听器作为线程内的全局对象而存在,在线程内部只要通过get方法就可以获取到监听器。而如果不采用ThreadLocal,那么我们能想到的可能是如下两种方法:第一种方法是将监听器通过参数的形式在函数调用栈中进行传递,第二种方法就是将监听器作为静态变量供线程访问。上述这两种方法都是有局限性的。第一种方法的问题时当函数调用栈很深的时候,通过函数参数来传递监听器对象这几乎是不可接受的,这会让程序的设计看起来很糟糕。第二种方法是可以接受的,但是这种状态是不具有可扩充性的,比如如果同时有两个线程在执行,那么就需要提供两个静态的监听器对象,如果有10个线程在并发执行呢?提供10个静态的监听器对象?这显然是不可思议的,而采用ThreadLocal每个监听器对象都在自己的线程内部存储,根本就不会有方法2的这种问题。
其它
Looper是与线程绑定的。具有一对一关系。