Android线程间的消息传递机制

android的线程间的通信可以理解成三个部分:消息的发送、消息的循环、消息的分发处理

消息是怎么发送的?

核心是理解sendMessage()里面做了哪些操作

  1. handler.sendMessage()
  2. handler.sendMessageDelayed()
  3. handler.sendMessageAtTime()
需要注意的是,sendMessageAtTime不是指要在这个时间插入这条消息,而是在这个时间将该消息分发出去
  1. handler.enqueueMessage()
  2. messageQueue.enqueueMessage()
  3. native->nativeWake()
  4. native->messageQueue.wake()
  5. native->mLooper.wake()

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

mWakeEventFd是一个计数器。

有两个线程,线程A和线程B
在这里插入图片描述
线程A有两种状态,运行、阻塞。监听eventfd事件的的navtive函数是阻塞的,当线程B往线程A消息队列发送消息,与此同时线程B通过eventfd写一个计数,此时会唤醒messageQueue中next函数内的无限for循环里面的,从messageQueue单链表中读取表头的操作

消息循环的过程是怎么样的?

消息循环是调用Looper.loop()

在这里插入图片描述
获取当前线程的looper,获取当前looper的messageQueue,开启无限循环,从messageQueue中读消息,如果msg为null,则阻塞,不为null,则将msg分发,其中target就是handler。以上有两个重点:

  • queue.next()是如何获取消息的?
  • msg.target.dispatchMessage(msg)是怎么分发消息的?

是如何处理消息分发的?

核心是理解dispatchMessage()里面做了什么操作
在这里插入图片描述

  1. 优先判断msg自身是否有callback,如果有,回调出去,即执行
msg.callback.run();

msg的callback是什么时候设置的呢?
是在handler.post(runnable)时候,执行sendMessageDelayed时,将Runnable对象赋值进message对象的callback中去
2. 判断handler是否有全局的callback,如果有,则掉全局的handleMessage函数。需要注意的是,如果回调的全局callback中的handleMessage函数,return 的是true,则不会再回调handler自身的handlerMessage函数,如果return的值是false,则会继续掉通handler自身的handlerMessage函数。一些hook技术就是通过设置全局的callback,并且handleMessage的返回值为false,中间修改msg的参数,这样,自身的handleMessage拿到的msg就是被修改之后的msg
3. 当前handler自身的handleMessage

从消息队列中获取下一条消息
在这里插入图片描述
在无限for循环中调用native层的nativePollOnce函数,这个函数其实是阻塞在for循环中的,目的是为了监听别的线程对当前线程喂消息,或者超时,就会唤醒返回,继续执行下面的代码。接着从消息队列(其实就是单链表)的表头取出一条消息,标记msg在使用中并返回。
是什么时候把msg标记为未使用的呢?
不是消息在recycle的时候,而是在Message.obtain()的时候,及将消息从空闲链表取出来的时候标记消息为未使用
超时时间默认为0,也就是说第一次无论如何都是会从消息队列读取消息的,如果没有读取到消息,这个超时时间可能就会被设置成-1了,会一直等待下次消息enqueue。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
创建handler:
Looper.myLooper()获取当前线程的looper,判断当前线程是否有looper,如果没有,则需手动创建Looper.prepare(),否则抛出异常
在prepare函数中会从sThreadLocal.get()获取当前线程的looper,如果不为null,则抛出异常,提示每个线程只允许有一个Looper实例。如果为null,则new 一个Looper对象并将其保存在sThreadLocal中,sThreadLocal.set(new Looper(quiteAllowed)).Looper实例化的时候有做了什么呢,创建MessageQueue的java层实例,并用mThread变量保存looper当前的线程信息。在实例化java层的MessageQueue的时候,执行native层的init初始化函数,初始化native层的messageQueue,在初始化native层的messageQueue的时候,同时初始化native层的Looper
子线程
sendMessage()->sendMessageDelayed()->sendMessageAtTime()->enqueueMessage->nativeWake() 标记eventFD计数,唤醒Looper.looper()–>queue.next()的阻塞,dispatchMessage

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值