Looper是什么
用于为线程运行消息循环的类。默认情况下,线程没有与之关联的消息循环。要创建一个,在要运行循环的线程中调用 prepare(),然后调用loop()让它处理消息,直到循环停止为止。与消息循环的大多数交互是通过 Handler类进行的。
意思大概就是让线程有处理消息的能力,并且这种能力是无限循环的,直到被停止为止。
简单使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
创建一个具有消息循环的线程,该线程中创建一个和该looper绑定的handler对象,然后点击事件中不断的去发送消息给looper循环,看下最后的效果如下:
18:17:45.459 12495-12538/com.example.myapplication E/[MainActivity]: 收到发送过来的消息:点击事件消息时间戳:5458
18:17:45.690 12495-12538/com.example.myapplication E/[MainActivity]: 收到发送过来的消息:点击事件消息时间戳:5690
18:17:45.887 12495-12538/com.example.myapplication E/[MainActivity]: 收到发送过来的消息:点击事件消息时间戳:5886
...省略
18:18:40.010 12495-12538/com.example.myapplication E/[MainActivity]: 收到发送过来的消息:点击事件消息时间戳:9
18:18:40.840 12495-12538/com.example.myapplication E/[MainActivity]: 收到发送过来的消息:点击事件消息时间戳:839
18:18:41.559 12495-12538/com.example.myapplication E/[MainActivity]: 收到发送过来的消息:点击事件消息时间戳:1558
可以看到我一直点击,一直有消息可以被处理,那么说明我创建的线程是一直运行的,并没有结束。那么looper具体是怎么实现的这样的功能的呢?
从源码了解loop原理
在分析源码之前,先看下整体的类图关系:
loop分析
我们从Looper.prepare();
这句代码开始分析:
1 |
|
1 2 3 4 5 6 7 8 9 10 |
|
可以看到调用了prepare()
方法后,接着调用了有参函数prepare:
1 2 3 4 5 6 |
|
sThreadLocal的泛型参数是Looper,那么知道Looper保存在了线程所持有的map容器中,首先就是判断sThreadLocal.get()
是否为空,这个方法在上一章说过,是根据当前线程来获取的,如果这个prepare方法在ui线程中调用那么返回的就是ui线程中的Looper,如果调用的是子线程中,那么返回的就是子线程的Looper了,如果不为空,抛出异常,意思就是一个线程只能持有一个Looper对象;如果为空的话,那么调用sThreadLocal的set方法将创建的Looper对象存放到对应线程的map容器中。
接着调用了loop函数:
1 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
大概是这样的,其中去掉了一些和业务无关的代码。
myLooper()
第一步调用myLooper()方法:
1 2 3 4 5 |
|