本网站(662p.com)打包出售,且带程序代码数据,662p.com域名,程序内核采用TP框架开发,需要联系扣扣:2360248666 /wx:lianweikj
精品域名一口价出售:1y1m.com(350元) ,6b7b.com(400元) , 5k5j.com(380元) , yayj.com(1800元), jiongzhun.com(1000元) , niuzen.com(2800元) , zennei.com(5000元)
需要联系扣扣:2360248666 /wx:lianweikj
一款Android平台的LivaData的消息总线框架
安卓巴士 · 675浏览量 · 发布于2021-02-08 +关注

作者codyer,源码ElegantBus,ElegantBus 是一款 Android 平台,基于 LivaData 的消息总线框架,这是一款非常 优雅 的消息总线框架。

如果对 ElegantBus 的实现过程,以及考虑点感兴趣的可以看看前几节自吹

如果只是想先使用的,可以跳过,直接到跳到使用说明

和常见 LivaData 实现的 EventBus 比较

消息总线使用反射入侵系统包名进程内 Sticky跨进程 Sticky跨 APP Sticky事件可配置化线程分发消息分组跨 App 安全考虑常驻事件 Sticky
LiveEventBus:white_check_mark::white_check_mark::white_check_mark::x::x::x::x::x::x::x:
ElegantBus:x::x::white_check_mark::white_check_mark::white_check_mark::white_check_mark::white_check_mark::white_check_mark::white_check_mark::white_check_mark:

来龙去脉

自吹

ElegantBus 支持跨进程,且支持跨应用的多进程,甚至是支持跨进程间的粘性事件,支持事件管理,支持事件分组,支持自定义事件,支持同名事件等。

之所以称之为最优雅的总线,是因为她不仅实现了该有的功能,而且尽量选用最合适,最轻量,最安全的方式去实现所有的细节。 更值得夸赞的是使用方式的优雅!

前言

随着 LifeCycle 的越来越成熟,基于 LifeCycle 的 LiveData 也随之兴起,业内基于 LiveData 实现的 EventBus 也如雨后春笋一般拔地而起。

出于对技术的追求,看过了无数大牛们的实现,各位大神们思路也是出奇的神通,最基础的 LiveData 版 EventBus 其实大同小异,一个单例类管理所有的事件 LivaData 集合。如果不清楚的可以随便网上找找

反正基本功能 LivaData 都支持了,实现 EventBus 只需要把所有事件管理起来就完事了。

业内基于 LiveData 实现的 EventBus,其实考虑的无非就是下面提到的五个挑战,有的人考虑的少,有的人考虑的多,于是各种方案都有。

ElegantBus 主要是集合各家之优势,进行全方面的考虑而产生的。

五个挑战 之 路途险阻

挑战一 : 粘性事件

  • 背景 LivaData 的设计之初是为了数据的获取,因此无论是观察开始之前产生的数据,还是观察开始之后产生的数据,都是用户需要的数据,只要是有数据,当 LifeCycle 处于激活状态,数据就会传递给观察者。这个我们称之为 粘性数据。 这种设计对于事件来说有时候就不那么友好了,之前的事件用户可能并不关心,只希望收到注册之后发生的事件。

挑战二 : 多线程发送事件可能丢失

  • 背景 同样是因为使用场景的原因,LivaData 设计在跨线程时,使用 post 提交数据,只会保留最后一次数据提交的值,因为作为数据来说,用户只需要关心现在有的数据是什么。

挑战三 : 跨进程事件总线

  • 背景 有时候我们应用需要设置多进程,不同模块可能允许在不同进程中,因为单例模式每个进程都有一份实体,所有无法达到跨进程,这时候设计 IP 方案选择。

  • 说明 这里提一下为什么不选用广播方式,对广播有一定了解的都知道,全局广播会有信息泄露,信息干扰等问题,而且开销也比较大,因此全局广播并不适合这种情况。 也许有人会说可以用本地广播,然而,本地广播目前来说并不是很好的选择。

Google 官方也在 LocalBroadcastManager 的说明里面建议使用 LiveData 替代: 原文地址

原文如下:

2018 年 12 月 17 日

版本 1.1.0-alpha01 中将弃用 androidx.localbroadcastmanager。

原因

LocalBroadcastManager 是应用级事件总线,在您的应用中使用了层违规行为;任何组件都可以监听来自其他任何组件的事件。 它继承了系统 BroadcastManager 不必要的用例限制;开发者必须使用 Intent,即使对象只存在且始终存在于一个进程中。由于同一原因,它未遵循功能级 BroadcastManager。 这些问题同时出现,会对开发者造成困扰。

替换

您可以将 LocalBroadcastManager 替换为可观察模式的其他实现。合适的选项可能是 LiveData 或被动流,具体取决于您的用例。

更明显的原因是,本地广播好像并不支持跨进程~

挑战四 : 跨应用(权限问题以及粘性问题)

  • 背景 跨进程相对来说还比较好实现,但是有的时候用户会有跨应用的需求,其实这个也是 IPC 范畴,为什么单独提出来呢? 因为跨应用设计信息安全,权限校验问题,开放给其他应用,但是同时又要兼顾不被非法滥用。 因为数据只是进程内共享的,跨应用时,粘性事件将失效,如果要保持和单进程一样支持粘性事件,需要做特殊处理。

挑战五 : 兼容性,简洁性

  • 背景 一个好的事件总线需要很好的兼容,不同事件应该有个很好的管理,不会造成冲突,事件可以进行多种配置,如某事件是否支持跨进程,是否激活,属于什么分组等等。

使用说明

(一)ElegantBus 接入配置

1、项目级别 gradle 添加依赖 目前使用的是 jitPack

allprojects {
    repositories {
    ...
    maven { url 'https://jitpack.io' }
}
}


2、在应用 gradle 文件中添加 ElegantBus 最新版本依赖

def version = "2.0.0"
dependencies {
    implementation "com.github.codyer.ElegantBus:core:$version" // 不需要跨进程时使用
//  implementation "com.github.codyer.ElegantBus:ipc-aidl:$version" // 跨进程时使用(方式 1:aidl 实现,已经包含 core)
//  implementation "com.github.codyer.ElegantBus:ipc-messenger:$version" // 跨进程时使用(方式 2:messenger 实现,已经包含 core)
//    annotationProcessor "com.github.codyer.ElegantBus:compiler:$version"// 需要事件自动管理时使用
}


如果不需要跨进程,以上两步配置就可以了,如果需要跨进程,第二步选择一个跨进程的方式,并添加第三步配置,且设置第四步。

3、在应用 gradle 文件中的 manifestPlaceholders 配置是否支持跨 App,以及主 App 的 applicationId

manifestPlaceholders = [
    BUS_SUPPORT_MULTI_APP  : true,// 是否支持跨 App
    BUS_MAIN_APPLICATION_ID: "com.example.bus" // 肯定会被安装的主 app 的 applicationId
]


为了 App 安全性,必须使用相同的密钥签名的 App 才可以设置为一个公用组,否则 Debug 模式下会抛出异常,Release 模式下会输出 error 信息。

4、分别在应用的 Application 的 onCreate 和 onTerminate 方法中添加开始支持多进程和结束多进程

public class BusApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        ElegantBus.setDebug(true);// 可以打开日志开关
        ElegantBusX.supportMultiProcess(this);
    }

    @Override
    public void onTerminate() {
        ElegantBusX.stopSupportMultiProcess();
        super.onTerminate();
    }
}


以上几步就完成了使用 ElegantBus 的全部配置,下面进入使用环节

(二)ElegantBus 使用说明

1、 发送事件

最简单方式就是直接一句

ElegantBus.getDefault("EventA").post(new Object());
ElegantBus.getDefault("EventA").post("eventA");
ElegantBus.getDefault("EventA").post(888888);


可以在任何线程发送都是 OK 的,考虑大部分是没有跨进程需求的,所以这里默认,这种最简单的方式,这个事件 EventA 是不支持跨进程的。 如果要进行跨进程可以使用重载函数进行设置,重载函数如下:

ElegantBus.getDefault(String group, String event, Class<T> type, boolean multiProcess);


以下说的激活状态指页面处于 RESUMED 情况

2、 接收事件

接收事件也很简单:

  • 常规事件

生命周期相关的事件,只有页面处于激活状态才会收到事件,如果在页面非激活状态时有事件发生,等页面激活(OnResume)时会收到事件。

ElegantBus.getDefault("EventA").observe(this, new ObserverWrapper<Object>() {
            @Override
            public void onChanged(final Object value) {
                ElegantLog.d(value.toString());
            }
        });


  • 粘性事件

如果观察之前有事件发生,也可以收到事件,eg:A 页面发送事件,打开 B 页面,B 页面开始观察,用粘性事件也可以收到。

ElegantBus.getDefault("EventA").observeSticky(this, new ObserverWrapper<Object>() {
            @Override
            public void onChanged(final Object value) {
                ElegantLog.d(value.toString());
            }
        });


  • 常驻事件

和生命周期无关,无论页面是否在激活状态,都可以收到事件,前提是页面已经打开了。

ObserverWrapper<Object> foreverObserverWrapper;
ElegantBus.getDefault("EventA").observeForever(foreverObserverWrapper = new ObserverWrapper<Object>() {
            @Override
            public void onChanged(final Object value) {
                ElegantLog.d(value.toString());
            }
        });
// 常驻事件要自己取消注册,避免内存泄露
ElegantBus.getDefault("EventA").removeObserver(foreverObserverWrapper);


  • 其实普通事件和常驻事件都支持粘性事件

只要创建 ObserverWrapper 时设置 sticky = true 就可以; ElegantBus 提供了默认构造函数如下:参数 true 表示粘性事件

new ObserverWrapper<Object>(true) {
        @Override
        public void onChanged(Object value) {}
   })


以上简单的使用就介绍完毕了

高级特性

  • 可以发现,上面的方式,接收的数据类型是 Object 的,因此,只要是同名的事件,无论发送的是什么类型,观察者都可以接收到。 为了对事件进行统一管理,防止事件冲突,事件大小写等拼写错误带来的问题,个人不建议直接使用这种方式

推荐使用事件定义方式

事件定义

  • 先上例子

    @EventGroup(value = "TestScope", active = true)
    public class EventDefine {
      @Event(description = "eventInt 事件测试", multiProcess = false, active = true)
      Integer eventInt;
    
      @Event(description = "eventString 事件测试", multiProcess = true, active = true)
      String eventString;
    
      @Event(description = "eventBean 事件测试", multiProcess = true, active = true)
      JavaBean eventBean;
    }


    说明

    其实事件定义只用到两个注解

1)、@EventGroup 使用在 class 上,定义事件分组名,是否激活

2)、@Event 使用在变量上,定义具体 事件描述,是否激活,是否支持多进程

定义完注解后,通过前面导入的注解处理器 annotationProcessor ,ElegantBus 会自动生成以 EventGroup 定义的分组名的事件总线 例如上面的定义就会生成一个 TestScopeBus

然后我们所有地方就可以直接使用这个事件总线进行事件管理。

  • 发送事件

    TestScopeBus.eventInt().post(888);
    TestScopeBus.eventString().post("新字符串");
    TestScopeBus.eventBean().post(new JavaBean());


  • 接收事件

    TestScopeBus.eventInt().observe(owner, new ObserverWrapper<Integer>() {
      @Override
      public void onChanged(final Integer value) {
          ...
      }
    });


    事件回调在非 UI 线程执行

    默认事件是在主线程回调的,如果想在非主线程回调,设置 ObserverWrapper.uiTread = false,同时提供默认构造函数设置是否在 UI 线程回调。

 


源码使用过程中,如无法搭建或有增加其他功能需求,可联系QQ:236-0248-666 ,付费搭建安装修改服务!
温馨提示:网站源码只作为学习或研究使用,如需商业使用请购买正版!

相关推荐

一个Android快速图片加载框架BaseImageLoader

相关信息 一路向西 · 725浏览 · 2020-12-28 08:45:18
一个高度自定义的安卓视频框架案例

相关信息 iamitnan · 601浏览 · 2019-12-26 17:57:17
学习各种项目架构的知乎日报安卓案例源码

相关信息 冷月葬花魂 · 688浏览 · 2019-07-08 16:05:56
Android快速开发框架RapidDevelop

相关信息 kenrry1992 · 606浏览 · 2019-06-24 14:19:20
一个安卓Kotlin轻量级依赖注入框架

相关信息 匿名 · 577浏览 · 2019-04-09 09:50:51
加载中

0评论

评论
我是安卓代码搬运工,汇集了很多非常不错的android源码项目案例,希望能够帮到需要学习的朋友。
  • 源码信息
  • 所需 0 点数
  • 源码作者:匿名作者
  • 源码大小:217.133 KB
  • 源码类型:android源码
  • 显示语言: 简体中文
  • 运行环境:未知
分类专栏
小鸟云服务器
扫码进入手机网页