Looper和Handler

1.处理消息过程

1.1 从HandlerThread开始

带有一个Looper的Thread,然后这个Looper可以被使用去创建Handler.

既然是一个Thread,那我就从run()开始!!进入Looper中.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-60gdCnor-1625126859347)(/home/lxr/.config/Typora/typora-user-images/image-20210630111858520.png)]

1.1.1 Looper.prepare();

为当前线程初始化一个Looper对象,在调用Looper.loop()之前必须先调用该方法,结束时调用Looper.quit()

在这里插入图片描述
其中sThreadLocal是Looper中的一个静态常量.ThreadLocal用来存储线程的自己的成员变量,只与某个线程相关连;在Looper中定义,是存储当前线程的Looper对象(即,每个线程都拥有自己的Looper类型的变量)

1.1.2 mLooper = Looper.myLooper();

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y9MQJLZp-1625126859351)(/home/lxr/.config/Typora/typora-user-images/image-20210630111314151.png)]
获取当前线程的Looper对象.

1.1.3 Looper.loop();

在当前线程中运行消息队列,loop()方法不会自己主动停止,需要调用quit()方法来停止.
在这里插入图片描述

1.2.Handler

1.2.1 Handler.dispatchMessage()

处理消息
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W1XCfC44-1625126859354)(/home/lxr/.config/Typora/typora-user-images/image-20210630133104378.png)]
1)handleCallback():Message中的callback成员属性是Runnable类型的,调用run()方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iEtC14Og-1625126859354)(/home/lxr/.config/Typora/typora-user-images/image-20210630134620496.png)]
2)如果Message没给callback赋值,就调用创建Handler时传进来的Callback.handleMessage(),或者执行Handler的子类实现的handleMessage.

以上是处理消息的过程,接下来分析Handler如何将消息发送到Looper的消息队列中.

2.发送消息过程

Handler发消息的方法:

sendMessage(Message msg),

sendEmptyMessage(int what),

sendEmptyMessageDelayed(int what, long delayMillis),

sendMessageDelayed(Message msg, long delayMillis)

最终都是调用的sendMessageAtTime(Message msg, long uptimeMillis)方法.

2.1 Handler.sendMessageAtTime(Message msg, long uptimeMillis)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gIqJMg6B-1625126859354)(/home/lxr/.config/Typora/typora-user-images/image-20210630140424827.png)]
其中,mQueue是当前线程中Looper的消息队列MessageQueue.uptimeMillis等于当前系统开机的时间+delayMillis

2.2 Handler.enqueueMessage()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KGjU0oEW-1625126859355)(/home/lxr/.config/Typora/typora-user-images/image-20210630140941296.png)]

3.MessageQueue

从上面的分析可以看出,消息链表是MessageQueue比较重要的部分,接下来主要分析MessageQueue中的next()和enqueueMessage()

3.1 MessageQueue.next()

  1. mPtr是native层消息队列的地址,当mPtr=0的时候,代表调用的dispose()方法,代表消息队列已经被释放了.
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-djdVkcC5-1625126859355)(/home/lxr/.config/Typora/typora-user-images/image-20210630200013451.png)]
    mPtr在new MessageQueue时被初始化,调用nativeInit()方法,该方法是一个native方法,实际的实现在android_os_MessageQueue.cpp中
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N6fE9mFD-1625126859356)(/home/lxr/.config/Typora/typora-user-images/image-20210630200601997.png)]
    NativeMessageQueue的构造主要将成员变量mLooper赋值,与java层类似,Looper也是从当前线程中get该线程的Looper对象.
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iVrkqX0H-1625126859357)(/home/lxr/.config/Typora/typora-user-images/image-20210701133824448.png)]

  2. pendingIdleHandlerCount该局部变量指的是IdleHandler对象的数量,因为后面它的赋值是mIdleHandlers.size(),如果使用的Handler没有继承IdleHandler类,该变量在后面会被赋值为0,因为它不影响主要的循环逻辑,因此不过多描述.

    Binder.flushPendingCommands():当后续操作会引起线程阻塞就调用该方法,具体的作用还不太了解.
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IZgLz9Bq-1625126859358)(/home/lxr/.config/Typora/typora-user-images/image-20210701135444716.png)]

  3. nativePollOnce是一个阻塞方法,利用native层的epoll(Linux的管道机制)来实现,用来控制sendMessageAtTime时传入的uptimeMillis.

    如果,nextPollTimeoutMillis=-1,则一直阻塞

    ​ nextPollTimeoutMillis=0,不阻塞直接返回

    ​ nextPollTimeoutMillis>0,最长阻塞nextPollTimeoutMillis毫秒,但如果其中程序被唤醒就直接返回.

    因此,根据后续的代码可以看出,当链表为空的时候,nextPollTimeoutMillis=-1,该线程会一直阻塞,阻塞时对CPU资源的占用等极低.
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JIUWtjoQ-1625126859358)(/home/lxr/.config/Typora/typora-user-images/image-20210701143234902.png)]
    4.最后就是从消息链表中取消息了,分3部分.
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E7mWWwbi-1625126859358)(/home/lxr/.config/Typora/typora-user-images/image-20210701144834183.png)]
    1)第一块判断:msg != null && msg.target == null,该判断条件是判断该msg是否是同步屏障,如果是同步屏障是找到异步消息,然后取出该异步消息.
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hTWxoi9q-1625126859359)(/home/lxr/.config/Typora/typora-user-images/image-20210701152050595.png)]
    同步屏障:Message分为3种消息,普通消息,消息屏障,异步消息.消息屏障中的target没有赋值,它的作用是用来保障它身后的异步消息比同步消息先被取出去处理.

​ 通过postSyncBarrier(times)方法,将消息屏障根据when插入到消息链表中.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NB93w3hE-1625126859359)(/home/lxr/.config/Typora/typora-user-images/image-20210701151538618.png)]
2)第二块now < msg.when,如果目前时间还小于当前要取出的消息的when,则重新设置阻塞时间.
​	[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jq76ZNSh-1625126859360)(/home/lxr/.config/Typora/typora-user-images/image-20210701152109240.png)]
3)第三块,就是将msg取出
​	[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5w3impKO-1625126859360)(/home/lxr/.config/Typora/typora-user-images/image-20210701152120387.png)]

3.2 MessageQueue.enqueueMessage()

  1. msg.markInUse():将要插入链表中的消息设置正在use.

​ when < p.when:判断当前要入队的消息的时间是否小于队列中头结点的消息的时间, 如果小于,就将当前消息设置为头结点.

​ 其中mMessages是队列头节点.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XeGrZfHs-1625126859360)(/home/lxr/.config/Typora/typora-user-images/image-20210701154923033.png)]
​ 2. 向队列中插入msg,逐个对比消息中的when,如果队列中的when大于msg的when了,就插入
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GzQu6KVy-1625126859361)(/home/lxr/.config/Typora/typora-user-images/image-20210701160305455.png)]
3. 判断当前线程是否阻塞,若阻塞,唤醒线程.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c8bkva7a-1625126859361)(/home/lxr/.config/Typora/typora-user-images/image-20210701160444207.png)]

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值