查看原文
其他

Android 应用内通信 - LocalBroadcast

2017-05-04 承香墨影 承香墨影

版权声明:

本公众号发布的所有文章,均属于原创,版权归本公众号所有。

未经允许,不得转载。

一、前言

最开始的时候,Android 下的 Broadcast 都是全局的,发出去的广播,只要有匹配的接收者,就可以收到广播。

而在 Support v4 : 21 之后,提供了一种新的 Broadcast 的形式,就是 LocalBroadcast,它主要用于在同一个应用中,不同组件之间,发送和接收 Broadcast。

二、LocalBroadcast 因何存在

BroadcastReceiver 在设计之初,就是想从全局的角度去设计一个方便不同应用程序之间进行通信的组件。而这样的一个开放的设计,对单个应用程序而言,BroadcastReceiver 是存在各种安全问题的。

而 LocalBroadcast 就是因为这个而存在的,顾名思义,它就是为了在同一个应用程序内,进行通信的组件。它通过 LocalBroadcastManager (以下简称 LBM),来实现注册、解注、发送广播等操作。

它和原有的 BroadcastReceiver 相比而言,有什么好处:

  1. 因 LocalBroadcast 只在本应用内,所以完全无需担心隐私数据被泄露的问题。
  2. LocalBroadcast 的发送和接收更可控。
  3. 比原有的 BroadcastReceiver 更高效(后面会讲到)。

三、如何使用 LocalBroadcast

LocalBroadcast 通过 LocalBroadcastManager 来管理,在 LBM 中,提供了普通广播使用的对应的 API,通过 LBM 中提供的 API,就可以完成对本地广播的操作,使用方式和普通广播无异。

LBM 是一个单例对象,可以通过 LocalBroadcastManager.getInstance(Context) 方法获取到。

LBM 的使用,其实没什么好说的,直接上例子。

首先,定义一个 BroadcastReceiver ,然后在一个 Activity 的生命周期内,分别注册和解注它,然后监听一个按钮的点击,用于发送 LocalBroadcast。

正常来说,使用 sendBroadcast() 是一个异步的操作,它不会堵塞住线程,同时 LBM 也提供了对应的同步操作方法,sendBroadcastSync()

四、LBM 的原理

接下来就来探究一下 LBM 的实现原理。本身普通的广播为了实现跨进程,使用了 Binder 机制,而 LocalBroadcast 上面介绍的会比普通广播跟高效,那么接下来就看看 LBM 的实现原理,是如何做到更高效的。

LBM 本身是一个单例的实现,也就是说,在当前进程的生命周期内只有一个 LBM 对象。

直接看 LBM 的构造方法。

可以看到,在其私有的构造方法中,实际上创建了一个基于主线程的 Looper 的 Handler,在这个 Handler 中,调用 executePendingBroadcasts() 方法,从方法名上,猜测这个方法是对接收到的广播进行处理。

接下来就来证实我们的猜测。

先看看注册接收者的 registerReceiver() 方法。

可以看到,在registerReceiver() 方法中,主要是操作了两个对象:mReceivers、mActions,它们都是 HashMap 类型的集合。

mReceivers 主要用于维护一个 BroadcastReceiver 对象和它的 IntentFilter 对象的对应关系。主要是为了方便在 unregisterReceiver() 方法中,快速的移除它,并且它也作为同步对象锁限制一些行为的同步访问。

而 mActions 则维护了一个以 action 为 key,ReceiverRecord 对象为 value 的对应关系。这样可以方便通过 action 找到与之匹配的 ReceiverRecord。而 ReceiverRecord 是一个内部类,主要用于存储 receiver 和 IntentFilter。

再来看看 unregisterReceiver() 方法,其实非常的简单,它只是按照条件,移除了 mReceivers 和 mActions 两个对象中存储的 BroadcastReceiver。

最关键的 sendBroadcast() 方法,看看它最终是如何发送这个 LocalBroadcast 的。

虽然看着挺多代码的,但是实际上它的处理方式很简单。先从 mActions 中取出对应的 ReceiverRecord 对象,然后在根据 IntentFilter 匹配出符合条件的 Receiver,再将其保存到 mPendingBroadcasts 对象中,最后发送一个 MSG_EXEC_PENDING_BROADCASTS 的消息给 mHandler。

后续我们就已经知道了,mHandler 接收到 MSG_EXEC_PENDING_BROADCASTS 消息之后,就会去执行 executePendingBroadcasts() 方法。

到这里就清晰了,它会将之前暂存在 mPendingBroadcasts 中的对象全部取出来,然后循环调用其 onReceiver() 方法,将其消费掉,完成此次广播的发送。

那再看看同步方法 sendBroadcastSync() 方法中是如何实现的,

可以看到,它实际上是调用 sendBroadcast() 之后,立即调用 executePendingBroadcasts() 方法去执行。这样因为在其中有同步对象锁,并且也有对 mPendingReceivers 中数量的校验,所以最终,发送给 mHandler 的消息执行的 executePendingBroadcasts() 方法的时候,对应的 mPendingReceivers 已经被消费掉清空了,就会被过滤掉,实际上是一次无意义的调用。

到此,基本上就已经完全了解了 LocalBroadcastManager 的所有细节,它之所以比普通广播跟高效,是因为其中并没有利用 Binder ,而是借助 Handler 来实现应用内的通信,自然安全性更好,效率更高。

五、小结

其实 LocalBroadcastManager 实现的效果类似一个 EventBus 的效果,更多的情况下,还是推荐使用类似 EventBug 这类成熟的开源库来完成我们应用内通信的需求。当然,LocalBroadcastManager 的思路还是有值得我们借鉴的地方的。


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存