Android Loop机制中Looper与handler详细分析

本文详细分析了Android中的Looper和Handler机制,解释了Looper如何为线程提供消息循环,以及Handler如何用于发送和处理消息。通过实例展示了Looper在主线程和子线程中的简单使用,并通过源码分析了loop()和handleMessage()的工作流程,探讨了同步屏障消息的用途和异步消息的处理方式。最后,总结了Handler的消息类型和发送过程,阐述了Looper、Handler和消息队列之间的关系。
摘要由CSDN通过智能技术生成

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

public Handler handler;

public void looperThread(){

    new Thread(new Runnable() {

        @Override

        public void run() {

            Looper.prepare();

            handler = new Handler(Looper.myLooper(),new Handler.Callback() {

                @Override

                public boolean handleMessage(Message msg) {

                    Log.e(TAG,"收到发送过来的消息:"+msg.obj.toString());

                    return false;

                }

            });

            Looper.loop();

        }

    }).start();

}

@Override

public void onClick(View view) {

    Message message = Message.obtain();

    message.obj = "点击事件消息时间戳:"+System.currentTimeMillis()%10000;

    handler.sendMessage(message);

}

创建一个具有消息循环的线程,该线程中创建一个和该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

Looper.prepare();

1

2

3

4

5

6

7

8

9

10

public final class Looper {

    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

    private static Looper sMainLooper;  // guarded by Looper.class

    final MessageQueue mQueue;

    final Thread mThread;

    ...省略

    public static void prepare() {

        prepare(true);

    }

    ...省略

可以看到调用了prepare()方法后,接着调用了有参函数prepare:

1

2

3

4

5

6

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));

}

sThreadLocal的泛型参数是Looper,那么知道Looper保存在了线程所持有的map容器中,首先就是判断sThreadLocal.get()是否为空,这个方法在上一章说过,是根据当前线程来获取的,如果这个prepare方法在ui线程中调用那么返回的就是ui线程中的Looper,如果调用的是子线程中,那么返回的就是子线程的Looper了,如果不为空,抛出异常,意思就是一个线程只能持有一个Looper对象;如果为空的话,那么调用sThreadLocal的set方法将创建的Looper对象存放到对应线程的map容器中。

接着调用了loop函数:

1

Looper.loop();

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

public static void loop() {

    final Looper me = myLooper();

    ...省略

    final MessageQueue queue = me.mQueue;

    for (;;) {

        Message msg = queue.next(); // might block

        if (msg == null) {

            return;

        

        ...省略

        try {

            msg.target.dispatchMessage(msg);

        } finally {

           ...省略

        }

        ...省略

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jh035

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值