android 接收通知流程,android Handler消息流程梳理

消息机制概述

Android 系统在设计的初期就已经考虑到了 UI 的更新问题,由于 Android 中的 View 是线程不安全的,然而程序中异步处理任务结束后更新 UI 元素也是必须的。这就造成了一个矛盾,最简单的解决方法肯定是给 View 加同步锁使其变成线程安全的。这样做不是不可以,只是会有两点坏处:

1 加锁会有导致效率底下

2 由于可以在多个地方更新 UI,开发就必须很小心操作,开发起来就很麻烦,一不小心就出错了。

基于以上两个缺点,这种方式被抛弃。于是,设置一个线程专门处理 UI控件的更新,如果其他线程也需要对 UI 进行更新,不好意思,您把您想做的告诉那个专门处理 UI 线程的家伙,让它帮你做。大家各有各的任务,井水不犯河水,各司其职,效率才会高,

那么您也看出来了,消息机制其实可以很简单的用一句话概括,就是:其他线程通过给特定线程发送消息,将某项专职的工作,交给这个特定的线程去做。比如说其他线程都把处理 UI 显示的工作通过发送消息交给 UI 线程去做。

消息机制相关类

消息主要设计到下面几个类:

Handler:这是消息的发出的地方,也是消息处理的地方。

Looper:这是检测消息的地方。

MessageQueue: 这是存放消息的地方,Handler 把消息发到了这里,Looper 从这里取出消息交给 Handler 进行处理

Message:呜呜呜…他们发的是我,处理的也是我。

Thread:我在这里专门指代的是,处理消息的线程。消息的发送是在别的线程。

源码跟踪--梳理消息发送接收过程

咱们先来走一个在子线程想要更新UI的流程:

1 在主线程新建一个 Handler 对象,在构造方法中传入一个实现 Handler.Callback 接口的匿名类的对象,实现接口中的 handleMessage 方法

2 在非 UI 线程使用 Handler 的 sendMessage 或者 post 方法发送一个消息

3 然后 handleMessage 方法会在不久的将来马上执行,实现更新 UI 的操作。

关于类Handler:

Handler 拥有 Looper 的引用,通过得到 Looper 对象获得 Looper 中保存的 MessageQueue 对象

Handler 拥有 MessageQueue 的引用,使 Handler 得以拥有发送消息(将 Message 放入 MessageQueue )的能力

Handler 拥有 Handler.Callback 的引用,使得 Handler 可以方便的进行消息的处理。

根据上面的1 2 3 步,我们跟进源码看看:

9cd351ac46a7

1 创建handler

9cd351ac46a7

handler构造方法源码

在handler中获取了mLooper,mQueue对象,主要看mLooper是怎么获取的,Looper.myLooper();再跟进这个方法:

9cd351ac46a7

Looper类

可以看到是由ThreadLocal维护的,我们知道ThreadLocal可以保存对应线程的变量,那么必定保存了当前线程的Looper。我们查找ThreadLocal.set()方法:

9cd351ac46a7

Looper类方法

可以看到是在调用Looper.prepare()时设置的,在主线程中是谁调用Looper.prepare()的呢?没错,就是ActivityThread(主线程),在创建主线程的main方法里调用:

9cd351ac46a7

ActivityThread中的main方法

那么就可以确定,上面ThreadLocal存储的Looper就是主线程的Looper。mQueue自然也是主线程的Looper的变量。然后就看发消息了,看看 Handler.sendMessage 干了啥,

9cd351ac46a7

handler类发送消息

可以看到,Handler类中发送消息最后调用了MessageQueue的enqueueMessage()方法,并且把msg.target设置成了handler本身,这在之后分析中用到,继续跟进:

9cd351ac46a7

MessageQueue类方法

到这里,我们发现handler已经成功法一个消息放到了主线程的MessageQueue中了,接下来就是取消息操作了。只要主线程中调用了Looper.loop()方法,那就启动了一个死循环,会从MessageQueue中不停的取消息(无消息就阻塞)。

9cd351ac46a7

Looper的loop方法

可以看到,loop()方法开启了一个死循环,不断从MessageQueue取消息,并调用msg.target(Handler)去调用dispatchMessage(msg)方法。那就是调用了handler的dispatchMessage(msg)方法

9cd351ac46a7

handler类方法

这里分三种情况,

* 如果Message中callback对象不为空(这是调用handler.post(Runnable)方法发送的消息),就调用callback的run方法

* 否则如果创建Handler的时候如果设置了Callback就调用创建时候的传入的实现Handler.Callback接口的类的对象的handleMessage方法,看这就是回调方法被调用的地方。

* 再如果没有mCallback对象,就调用自身的handleMessage方法,为了Handler的子类复写了该方法的时候,方便调用,如,IntentService里的ServiceHandler就是继承自Handler的,并且重写了handleMessage方法。

我们创建handler时实现了Handler.Callback接口,所以就跳到一开始创建handler的地方处理消息啦。

小结

ok,再整理一下思路:1 在主线程创建handler实现Handler.Callback接口,主线程一运行就存在Loop和MessageQueue。2 其他线程通过主线程的该handler发送msg,发送到了主线程的MessageQueue。3 主线程的Looper从MessageQueue循环取消息,取到该消息就调用msg.target(handler).dispatchMessage(msg),也就跟着调用了handler的handleMessage()。

另外,如果非主线程要创建handler对象,必须要调用Looper.prepare()创建一个Looper和Looper.loop()开启消息循环。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值