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

事件总线

  • 组件化层级障碍:

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

这时就需要用到基础层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

与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

其项目地址如下:
https://github.com/JinYangLiu/LiveEventBus
另外的项目SmartEventBus,基于LiveEventBus实现,能让你定制自己的消息总线
https://github.com/JinYangLiu/SmartEventBus

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

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

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

1.EventBus,RxBus: 将xxEvent消息容器和事件总线框架的依赖放到base module,其他模块组件依赖于base module;
但是这样每个模块改动都需要增删改baseModule中的消息容器, 组件化要求功能模块独立, 各组件应该尽量避免影响base module;

  1. LiveDataBus: 无需建立消息模型,但无法想前两者一样拥有类名索引,无法引导正确的编写代码,也无法传递自定义实体到其他模块;
  2. 组件化中使用EventBus,RxBus,为了更大程度的解耦,可以独立出一个事件总线module,添加事件的实体都在这个module中,
    base module依赖 这个事件总线module对事件通信的解耦, 抽离事件到事件总线module中减少对base module的影响;
阅读全文
下载说明:
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.dandroid.cn/archives/19694,转载请注明出处。
0

评论0

显示验证码
没有账号?注册  忘记密码?