Android系统的组件通信机制,Android组件化架构 - 2. 组件间通信机制

本地广播LocalBroadcastManager

说到组件间通信第一个肯定想到广播BroadcastReceiver,但是这里要说的是一个更优的选择---本地广播LocalBroadcastManager;

优点:只在app内传播, 信息不会泄露,也不会被别人的广播干扰, 且比全局广播更高效;

缺点:但是本地广播传输消息时将一切都交给系统负责,无法干预传输中的步骤;

使用观察者模式

使用demo:

class LocalBroadcastActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

setContentView(R.layout.activity_local_broadcast)

testLocalBroadcast()

}

private lateinit var broadcastReceiver: BroadcastReceiver

private lateinit var lbm: LocalBroadcastManager

private val localAction = "com.ljy.publicdemo.localAction"

private fun testLocalBroadcast() {

broadcastReceiver = object : BroadcastReceiver() {

/**

* 接收并出列广播

*/

override fun onReceive(context: Context?, intent: Intent?) {

if (localAction == intent!!.action) {

val value = intent.getStringExtra("key_001")

LogUtils.d("key_001=$value, do something... ")

}

}

}

//创建

lbm = LocalBroadcastManager.getInstance(this)

//注册

lbm.registerReceiver(broadcastReceiver, IntentFilter(localAction))

}

private fun sendBroadcast() {

//发送

val intent = Intent(localAction)

intent.putExtra("key_001", "value_001")

lbm.sendBroadcast(intent)

}

fun onBtnClick(view: View) {

when (view.id) {

R.id.button_send_broadcast -> sendBroadcast()

}

}

override fun onDestroy() {

super.onDestroy()

//解绑

lbm.unregisterReceiver(broadcastReceiver)

}

}

本质:看一下LocalBroadcastManager源码

//构造方法如下,其本质还是用handler通信

private LocalBroadcastManager(Context context) {

mAppContext = context;

mHandler = new Handler(context.getMainLooper()) {

@Override

public void handleMessage(Message msg) {

switch (msg.what) {

case MSG_EXEC_PENDING_BROADCASTS:

executePendingBroadcasts();

break;

default:

super.handleMessage(msg);

}

}

};

}

//内部类ReceiverRecord:将receiver和intentFilter封装成ReceiverRecord对象,

private static final class ReceiverRecord {

final IntentFilter filter;

final BroadcastReceiver receiver;

boolean broadcasting;

boolean dead;

ReceiverRecord(IntentFilter _filter, BroadcastReceiver _receiver) {

filter = _filter;

receiver = _receiver;

}

}

//内部类BroadcastRecord:将ReceiverRecord对象封装在BroadcastRecord对象中

private static final class BroadcastRecord {

final Intent intent;

final ArrayList receivers;

BroadcastRecord(Intent _intent, ArrayList _receivers) {

intent = _intent;

receivers = _receivers;

}

}

//有三个集合

//一个以receiver为key、以ReceiverRecord列表为value的map

private final HashMap> mReceivers= new HashMap<>();

//一个以action为key,以ReceiverRecord列表为value的map

private final HashMap> mActions = new HashMap<>();

//BroadcastRecord对象的集合

private final ArrayList mPendingBroadcasts = new ArrayList<>();

//注册和解绑的源码就不贴了

//registerReceiver()就是装填mReceivers,mActions这两个map

//unregisterReceiver()就是清除mReceivers,mActions

//发送广播源码

public boolean sendBroadcast(@NonNull Intent intent) {

synchronized (mReceivers) {

//。。。省略部分源码,主要就是对intent中的信息进行校验

//最关键的是下面的装填mPendingBroadcasts,和发送handler消息

if (receivers != null) {

for (int i=0; i

receivers.get(i).broadcasting = false;

}

mPendingBroadcasts.add(new BroadcastRecord(intent, receivers));

if (!mHandler.hasMessages(MSG_EXEC_PENDING_BROADCASTS)) {

mHandler.sendEmptyMessage(MSG_EXEC_PENDING_BROADCASTS);

}

return true;

}

}

}

return false;

}

//还有一个同步发送广播的方法

public void sendBroadcastSync(@NonNull Intent intent) {

if (sendBroadcast(intent)) {

executePendingBroadcasts();

}

}

//上面源码看出一个至关重要的方法executePendingBroadcasts,才是真正调用广播处理的回调

void executePendingBroadcasts() {

while (true) {

final BroadcastRecord[] brs;

synchronized (mReceivers) {

final int N = mPendingBroadcasts.size();

if (N <= 0) {

return;

}

brs = new BroadcastRecord[N];

mPendingBroadcasts.toArray(brs);

mPendingBroadcasts.clear();

}

for (int i=0; i

final BroadcastRecord br = brs[i];

final int nbr = br.receivers.size();

for (int j=0; j

final ReceiverRecord rec = br.receivers.get(j);

if (!rec.dead) {

rec.receiver.onReceive(mAppContext, br.intent);

}

}

}

}

}

事件总线

组件化层级障碍:

由组件化架构图可以看出,组件间相互独立,没有依赖,也就没有关系,也就无法传递信息,那么要如何交流呢?

这时就需要用到基础层base module, 因为组件层的模块都依赖于基础层;

事件总线

Android中activity,fragment,service间信息传递相对复杂, 如果用系统级别的广播, 有耗时,容易被捕捉,无法干预,可传输数据类型少等弊端,

于是大佬们就搞出了事件总线;

下面是三种目前常用的事件总线框架:

1. EventBus:

一款针对Android优化的发布/订阅事件总线,主要功能是替代handler,intent,broadcast;

优点是开销小,代码优雅,将发送者和接收者解耦;

/**

* 演示eventBus的使用

*/

//1. 定义要传递的事件实体

data class TestEvent(val params: String)

class EventBusActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

setContentView(R.layout.activity_eventbus)

}

//2. 准备订阅者

@Subscribe(threadMode = ThreadMode.MAIN)

fun onMessageEvent(event: TestEvent) {

LjyLogUtil.d(event.params)

}

//3. 注册订阅者

override fun onStart() {

super.onStart()

EventBus.getDefault().register(this)

}

//4. 解绑订阅者

override fun onStop() {

super.onStop()

EventBus.getDefault().unregister(this)

}

fun onBtnClick(view: View) {

when (view.id) {

//5. 发送事件, 实际场景中发送事件的发送者一般在其他页面或模块中

R.id.btn_send_event -> EventBus.getDefault().post(TestEvent("测试一下事件发送"))

}

}

}

EventBus2.x的版本和3.x是有很大区别的:

1. 2.x使用的是运行时注解,采用了反射的方式对整个注册的类的所有方法进行扫描来完成注册,因而会对性能有一定影响;

2. 3.x使用的是编译时注解,Java文件会编译成.class文件,再对class文件进行打包等一系列处理。在编译成.class文件时,

EventBus会使用EventBusAnnotationProcessor注解处理器读取@Subscribe()注解并解析、处理其中的信息,

然后生成Java类来保存所有订阅者的订阅信息。这样就创建出了对文件或类的索引关系,并将其编入到apk中。

3. 从EventBus3.0开始使用了对象池缓存减少了创建对象的开销。

EventBus给Android开发者世界带来了一种新的框架和思想,就是消息的发布和订阅。这种思想在其后很多框架中都得到了应用。

2. RxBUs

RxBus不是一个库,而是一个文件,实现只有短短30行代码。RxBus本身不需要过多分析,它的强大完全来自于它基于的RxJava技术。

public class RxBus {

/**

* Instance of {@link Bus}

*/

private static Bus sBus;

/**

* Get the instance of {@link Bus}

*

* @return

*/

public static synchronized Bus get() {

if (sBus == null) {

sBus = new Bus(ThreadEnforcer.ANY);

}

return sBus;

}

}

RxBus有很多实现,如:

AndroidKnife/RxBus(https://github.com/AndroidKnife/RxBus)(即上面的代码)

Blankj/RxBus(https://github.com/Blankj/RxBus)

下面是使用rxbus的demo

//1. rxbus的实现类

package com.ljy.publicdemo.util;

import androidx.lifecycle.Lifecycle;

import androidx.lifecycle.LifecycleOwner;

import com.trello.lifecycle2.android.lifecycle.AndroidLifecycle;

import com.trello.rxlifecycle2.LifecycleProvider;

import java.util.Map;

import java.util.concurrent.ConcurrentHashMap;

import io.reactivex.Observable;

import io.reactivex.ObservableEmitter;

import io.reactivex.ObservableOnSubscribe;

import io.reactivex.subjects.PublishSubject;

import io.reactivex.subjects.Subject;

/**

* @Author: LiuJinYang

* @CreateDate: 2020/5/11 17:01

*/

public class RxBusUtil {

private volatile static RxBusUtil mDefaultInstance;

private final Subject mBus;

private final Map, Object> mStickyEventMap;

private RxBusUtil() {

mBus = PublishSubject.create().toSerialized();

mStickyEventMap = new ConcurrentHashMap<>();

}

public static RxBusUtil getInstance() {

if (mDefaultInstance == null) {

synchronized (RxBusUtil.class) {

if (mDefaultInstance == null) {

mDefaultInstance = new RxBusUtil();

}

}

}

return mDefaultInstance;

}

/**

* 发送事件

*/

public void post(Object event) {

mBus.onNext(event);

}

/**

* 使用Rxlifecycle解决RxJava引起的内存泄漏

*/

public Observable toObservable(LifecycleOwner owner, final Class eventType) {

LifecycleProvider provider = AndroidLifecycle.createLifecycleProvider(owner);

return mBus.ofType(eventType).compose(provider.bindToLifecycle());

}

/**

* 判断是否有订阅者

*/

public boolean hasObservers() {

return mBus.hasObservers();

}

public void reset() {

mDefaultInstance = null;

}

/**

* Stciky 相关

*/

/**

* 发送一个新Sticky事件

*/

public void postSticky(Object event) {

synchronized (mStickyEventMap) {

mStickyEventMap.put(event.getClass(), event);

}

post(event);

}

/**

* 根据传递的 eventType 类型返回特定类型(eventType)的 被观察者

* 使用Rxlifecycle解决RxJava引起的内存泄漏

*/

public Observable toObservableSticky(LifecycleOwner owner, final Class eventType) {

synchronized (mStickyEventMap) {

LifecycleProvider provider = AndroidLifecycle.createLifecycleProvider(owner);

Observable observable = mBus.ofType(eventType).compose(provider.bindToLifecycle());

final Object event = mStickyEventMap.get(eventType);

if (event != null) {

return observable.mergeWith(Observable.create(new ObservableOnSubscribe() {

@Override

public void subscribe(ObservableEmitter subscriber) throws Exception {

subscriber.onNext(eventType.cast(event));

}

}));

} else {

return observable;

}

}

}

/**

* 根据eventType获取Sticky事件

*/

public T getStickyEvent(Class eventType) {

synchronized (mStickyEventMap) {

return eventType.cast(mStickyEventMap.get(eventType));

}

}

/**

* 移除指定eventType的Sticky事件

*/

public T removeStickyEvent(Class eventType) {

synchronized (mStickyEventMap) {

return eventType.cast(mStickyEventMap.remove(eventType));

}

}

/**

* 移除所有的Sticky事件

*/

public void removeAllStickyEvents() {

synchronized (mStickyEventMap) {

mStickyEventMap.clear();

}

}

}

//2. 使用

class RxBusActivity:AppCompatActivity(){

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

setContentView(R.layout.activity_rx_bus)

registerRxBus()

}

private fun registerRxBus() {

RxBusUtil.getInstance().toObservable(this, TestEvent::class.java).subscribe(object : Observer {

override fun onSubscribe(d: Disposable) {

LjyLogUtil.d("onSubscribe:回调返回Disposable 对象,让观察者管理订阅状态, 例如取消订阅")

}

override fun onNext(event: TestEvent) {

LjyLogUtil.d("onNext:数据接收处理")

LjyLogUtil.d(event.params)

}

override fun onError(e: Throwable) {

LjyLogUtil.d("onError:发生异常,终止事件流")

}

override fun onComplete() {

LjyLogUtil.d("onComplete:事件流结束")

}

})

}

fun onBtnClick(view: View) {

when(view.id){

R.id.btn_rx_bus->RxBusUtil.getInstance().post(TestEvent("测试rxBus发送消息"))

}

}

}

//因为用了Rxlifecycle,推出activity时无需解绑

与EventBus相比的优点,其实也就是rxJava的优点:

1、RxJava的Observable有onError、onComplete等状态回调。

2、RxJava使用组合而非嵌套的方式,避免了回调地狱。

3、RxJava的线程调度设计的更加优秀,更简单易用。

4、RxJava可使用多种操作符来进行链式调用来实现复杂的逻辑。

5、RxJava的信息效率高于EventBus2.x,低于EventBus3.x。

那么技术选型时如何取舍呢?如果项目中使用了RxJava,则使用RxBus,否则使用EventBus3.x

3. LiveDataBus

LiveDataBus是基于LiveData实现的类似EventBus的消息通信框架,它是基于LiveData实现的,完全可以代替EventBus,RxBus;

为什么会有他呢?

Handler : 容易导致内存泄漏,空指针,高耦合,不利于维护

EventBus :原理实现复杂,无法混淆,需要手动绑定生命周期

RxBus:依赖于RxJava,包太大,影响apk大小,app启动时间

//初代实现如下

ublic final class LiveDataBus {

private final Map> bus;

private LiveDataBus() {

bus = new HashMap<>();

}

private static class SingletonHolder {

private static final LiveDataBus DATA_BUS = new LiveDataBus();

}

public static LiveDataBus get() {

return SingletonHolder.DATA_BUS;

}

public MutableLiveData getChannel(String target, Class type) {

if (!bus.containsKey(target)) {

bus.put(target, new MutableLiveData<>());

}

return (MutableLiveData) bus.get(target);

}

public MutableLiveData getChannel(String target) {

return getChannel(target, Object.class);

}

}

//使用

注册订阅:

LiveDataBus.get().getChannel("key_test", Boolean.class)

.observe(this, new Observer() {

@Override

public void onChanged(@Nullable Boolean aBoolean) {

}

});

发送消息:

LiveDataBus.get().getChannel("key_test").setValue(true);

4. 组件化事件总线的考量

其实目前常用的各种事件总线xxBus原理都差不多

那么在组件化项目中如何使用这些事件总线呢

1.EventBus,RxBus: 将xxEvent消息容器和事件总线框架的依赖放到base module,其他模块组件依赖于base module;

但是这样每个模块改动都需要增删改baseModule中的消息容器, 组件化要求功能模块独立, 各组件应该尽量避免影响base module;

LiveDataBus: 无需建立消息模型,但无法想前两者一样拥有类名索引,无法引导正确的编写代码,也无法传递自定义实体到其他模块;

组件化中使用EventBus,RxBus,为了更大程度的解耦,可以独立出一个事件总线module,添加事件的实体都在这个module中,

base module依赖 这个事件总线module对事件通信的解耦, 抽离事件到事件总线module中减少对base module的影响;

我是今阳,如果想要进阶和了解更多的干货,欢迎关注公众号”今阳说“接收我的最新文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值