2021-02-09 17:57:51 版本 : LiveDataBus核心原来如此简单
作者: 朱凡 于 2021年02月09日 发布在分类 / FM组 / FM_App 下,并于 2021年02月09日 编辑
 历史版本

修改日期 修改人 备注
2021-02-09 17:58:21[当前版本] 朱凡 格式调整
2021-02-09 17:57:51 朱凡 创建版本

LiveDataBus核心原来如此简单

luo_boke 2021-01-27 16:59:32 27 收藏

分类专栏: Android技术框架 文章标签: Android LiveDataBus

最后发布:2021-01-27 16:59:32 首次发布:2021-01-27 16:59:32

版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/luo_boke/article/details/113104570

版权


Android Architecture Components 系列目录

  1. LiveData原理深入浅出,透过源码看本质
  2. LiveDataBus框架抽丝剥茧后,原来如此简单
  3. Android Room数据库,用过你才知道好

LiveData通过源码看本质

  • 前言
  • 使用介绍
  • 结构分析
  • 总结

博客创建时间:2021.01.23
博客更新时间:2020.01.27

以Android studio 4.1.1来分析讲解,gradle=6.5,SdkVersion 30。如图文和网上其他资料不一致,可能是别的资料版本较低而已


前言

在博客《LiveData原理深入浅出,透过源码看本质 》中通过源码的详细分析,已经说明了LiveData的原理和使用流程。

本篇博客通过自己对LiveData的理解,封装名为LiveDataBus的通信框架。框架为纯Kotlin代码框架,其实框架实现很简单,原理完全基于LiveData。名字虽与网络上的LiveDataBus一样,功能也基本一致,但其内涵完全不一样,且看我一一剖析。

使用介绍

使用非常简单步骤分为:1.注册监听;2.数据更新后发布;3.收更新数据进行处理;4.注销监听。 使用流程如下代码,超级简单。

public class MainActivity extends AppCompatActivity {  @Override protected void onCreate(@Nullable Bundle savedInstanceState) {  super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViewById(R.id.btnSendOne).setOnClickListener(v -> // 2.数据更改后,数据发布 LiveDataBus.sendLiveString("单次点击") ); findViewById(R.id.btnMultiData).setOnClickListener(v -> {  new Thread(() -> {  int count = 0; while (count < 100) {  LiveDataBus.sendLiveString("复数点击"); try {  Thread.sleep(400); count++; } catch (InterruptedException e) {  e.printStackTrace(); } } }).start(); } ); //1.注册监听 observeForever(observer)方式注册 LiveDataBus.observeForever("LIVE_EVENT_BUS_COMMON_LIVE_STRING", observer); } private final Observer<String> observer = s -> // 3. 数据处理 Log.i("111111", s); @Override protected void onDestroy() {  super.onDestroy(); //4.注销观察 LiveDataBus.removeObserver("LIVE_EVENT_BUS_COMMON_LIVE_STRING", observer); } } 

注意:

  1. 观察者的注册方式有两种observe(owner, observer)和observeForever(observer)。如果采用了observe(owner, observer)方式注册,则不必进行第4步注销观察,当Activity处于DESTORY状态时observer会自动注销观察。
//1. 注册监听 observe(owner, observer)方式注册 LiveDataBus.observe(LiveDataBus.LIVE_EVENT_BUS_COMMON_LIVE_STRING, this, observer); //1.注册监听 observeForever(observer)方式注册 LiveDataBus.observeForever("LIVE_EVENT_BUS_COMMON_LIVE_STRING", observer); 
  1. 数据更新发布可以在UI线程中执行,也可在非UI线程中执行
findViewById(R.id.btnSendOne).setOnClickListener(v -> // 2.数据更改后,数据发布 LiveDataBus.sendLiveString("UI线程中发布数据更新") ); findViewById(R.id.btnMultiData).setOnClickListener(v -> {  new Thread(() -> {  int count = 0; while (count < 100) {  LiveDataBus.sendLiveString("非UI线程中发布数据更新"); try {  Thread.sleep(400); count++; } catch (InterruptedException e) {  e.printStackTrace(); } } }).start(); } ); 

结构分析

框架简单只有LiveDataBus 、 IConst、 LiveEventBus、 LiveDataReceiver四个文件,其核心是LiveEventBus类,对外暴露开放的操作类为LiveDataBus,其他两个类是辅助类文件
在这里插入图片描述
LiveEvent

LiveData 包装类,是事件真正运行操作的执行类,每个LiveEvent都必须包含一个MutableLiveData,同样数据的通行采用了观察者模式,所以LiveEvent中的方法实际分为两类,观察者的注册解绑和数据的更新发布。因LiveData中的相关方法都必须执行在主线程中,所以LiveEvent的调用者在执行时需要判断线程是否为主线程,确保LiveData的调用在主线程中。

1)观察者注册解绑
通信框架基于LiveData,自然含有其重要的三个注册及解绑的方法observe、observeForever、removeObserver。

/** * 注册一个Observer,生命周期感知,自动取消订阅 */ fun observe(owner: LifecycleOwner, observer: Observer<T>) {  if (isMainThread) {  liveData.observe(owner, observer) } else {  mainHandler.post {  liveData.observe(owner, observer) } } } /** * 注册一个Observer */ fun observeForever(observer: Observer<T>) {  if (isMainThread) {  liveData.observeForever(observer) } else {  mainHandler.post {  liveData.observeForever(observer) } } } /** * 通过observeForever的,需要手动调用该方法取消订阅 */ fun removeObserver(observer: Observer<T>) {  if (isMainThread) {  removeObserverInternal(observer) } else {  mainHandler.post {  removeObserverInternal(observer) } } } @MainThread private fun removeObserverInternal(observer: Observer<T>) {  liveData.removeObserver(observer) if (!liveData.hasObservers()) {  get().bus.remove(key) } } 

LiveEvent的观察者注册与解绑最终都是在主线程中调用了LiveData的对应方法,并没什么新意。


2)数据更新发布

数据发布提供三种法法post(value)、postDelay(value, delay)、broadcast(value)。该框架支持跨进程通信的实质是通过BroadCastReceiver通信

/** * 发送一个消息,支持前台线程、后台线程发送 */ fun post(value: T) {  if (isMainThread) {  liveData.setValue(value) } else {  mainHandler.post {  liveData.setValue(value) } } } /** * 延迟发送一个消息,支持前台线程、后台线程发送 * * @param delay 延迟毫秒数 */ fun postDelay(value: T, delay: Long) {  mainHandler.postDelayed({  liveData.setValue(value) }, delay) } /** * 发送一个消息,支持前台线程、后台线程发送 * 需要跨进程、跨APP发送消息的时候调用该方法 */ fun broadcast(value: T) {  if (isMainThread) {  sendBroad(key, value) } else {  mainHandler.post {  sendBroad(key, value) } } } @SuppressLint("SyntheticAccessor") private fun <T> sendBroad(key: String, value: T) {  appContext?.let {  val intent = Intent(IConst.ACTION) intent.putExtra(IConst.KEY, key) encode(intent, value) it.sendBroadcast(intent) } } 

注意:
通过sendBroad(key, value)方式发布数据时,需要确保参数appContext!=null,所以想要支持广播发送数据,需要调用LiveEventBus.supportBroadcast设置appContext。


LiveEventBus

LiveEvent的管理类,采用单例模式使得其实例在应用中总是唯一。该类中含有一个保存Key与LiveEvent一 一对应关系的MutableMap,通过Key可以快速获得想要操作的LiveEvent。

class LiveEventBus internal constructor() {  /** * LiveEvent 集合Map */ val bus: MutableMap<String, LiveEvent<*>> private var appContext: Context? = null /** * 单例模式,线程安全类型 */ private object SingletonHolder {  val DEFAULT_BUS = LiveEventBus() } companion object {  fun get(): LiveEventBus {  return SingletonHolder.DEFAULT_BUS } } init {  bus = HashMap() } @Synchronized fun <T> with(key: String): LiveEvent<T> {  var liveEvent = bus[key] return if (liveEvent == null) {  liveEvent = LiveEvent<T>(key) bus[key] = liveEvent
      liveEvent } else {  liveEvent as LiveEvent<T> } } } 

LiveDataReceiver

如果要使用本框架进行跨进程通信,请务必注册该BroadcastReceiver,这样才能接收来自其他进程发送而来的数据。

class LiveDataReceiver : BroadcastReceiver() {  fun getIntentFilter(): IntentFilter {  val intentFilter = IntentFilter() intentFilter.addAction(IConst.ACTION) return intentFilter } override fun onReceive(context: Context, intent: Intent) {  if (IConst.ACTION == intent.action) {  val key = intent.getStringExtra(IConst.KEY) ?: return val valueType = intent.getIntExtra(IConst.VALUE_TYPE, -1) if (valueType < 0) {  //没有合适的数据 return } when (DataType.values()[valueType]) {  DataType.STRING -> {  val value = intent.getStringExtra(IConst.VALUE) value?.let {  LiveEventBus.get().with<String>(key).post(it) } } DataType.INTEGER -> {  val value = intent.getIntExtra(IConst.VALUE, -1) value.let {  LiveEventBus.get().with<Int>(key).post(it) } } DataType.BOOLEAN -> {  val value = intent.getBooleanExtra(IConst.VALUE, false) value.let {  LiveEventBus.get().with<Boolean>(key).post(it) } } DataType.LONG -> {  val value = intent.getLongExtra(IConst.VALUE, -1) value.let {  LiveEventBus.get().with<Long>(key).post(it) } } DataType.FLOAT -> {  val value = intent.getFloatExtra(IConst.VALUE, -1f) value.let {  LiveEventBus.get().with<Float>(key).post(it) } } DataType.DOUBLE -> {  val value = intent.getDoubleExtra(IConst.VALUE, -1.0) value.let {  LiveEventBus.get().with<Double>(key).post(it) } } DataType.PARCELABLE -> {  val value: Parcelable? = intent.getParcelableExtra(IConst.VALUE) value?.let {  LiveEventBus.get().with<Parcelable>(key).post(it) } } DataType.SERIALIZABLE -> {  val value: Serializable? = intent.getSerializableExtra(IConst.VALUE) value?.let {  LiveEventBus.get().with<Serializable>(key).post(it) } } DataType.UNKNOWN -> throw UnknownError("不支持的数据类型!") else -> throw UnknownError("不支持的数据类型!") } } } } 

IConst

该类是一些常量类,一看就懂,不做解释了。

interface IConst {  companion object {  const val ACTION = "intent.action.ACTION_LIVE_DATA_BUS" const val KEY = "key" const val VALUE_TYPE = "value_type" const val VALUE = "value" } } enum class DataType {  /** * 数据枚举类 */ STRING, INTEGER, BOOLEAN, LONG, FLOAT, DOUBLE, PARCELABLE, SERIALIZABLE, JSON, UNKNOWN } 

总结

框架结构简单而功能强大,源码https://github.com/l424533553/LiveDataBus.git请自行查阅


相关链接

  1. LiveData原理深入浅出,透过源码看本质
  2. LiveDataBus框架抽丝剥茧后,原来如此简单
  3. Android Room数据库,用过你才知道好

博客书写不易,您的点赞收藏是我前进的动力,千万别忘记点赞、 收藏 ^ _ ^ !


  • 点赞
  • 评论
  • 分享

    x

    海报分享

    扫一扫,分享海报


  • 收藏
  • 打赏

    打赏

    C币 余额

    2C币 4C币 6C币 10C币 20C币 50C币

    确定

  • 举报
  • 关注 关注
  • 一键三连

    点赞Mark关注该博主, 随时了解TA的最新博文
  • 已标记关键词 清除标记

    LiveDataBus使用

    黄孝果的博客

    04-13 928

    LiveDataBus是在LiveData的基础上进行使用:LiveData使用 LiveDataBus import android.arch.lifecycle.LifecycleOwner; import android.arch.lifecycle.LiveData; import android.arch.lifecycle.MutableLiveData; import andr...

    表情包

    插入表情

    添加代码片

    • HTML/XML
    • objective-c
    • Ruby
    • PHP
    • C
    • C++
    • JavaScript
    • Python
    • Java
    • CSS
    • SQL
    • 其它


    还能输入1000个字符

    c# mvvm模式获取当前窗口_ViewModel_DataBinding核心原理【漫谈MVVM】

    weixin_39796140的博客

    11-22 18

    前言在开发模式的演进过程中 MVC,MVP,MVVM一一登上舞台。但是并不意味着MVVM一定就比MVC MVP优秀。不同的项目有不同的体量,开发中要根据项目体量选择合适的开发模式。市面上介绍mvvm的项目不在少数,但是看了很多,都在介绍源码原理,开发中的踩坑过程,而且有的是过时的资料,却很少见到能够直接从项目需求入手帮助不熟悉MVVM的开发者从入门到熟悉原理,再到框架优化的。这个空缺我来...

    LiveDataBus的实现比你想象中的简单

    u013750244的博客

    09-20 28

    原文链接:https://www.jianshu.com/p/9b00422fbcc1 为什么要用LiveData实现事件总线呢? LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。 LiveData 具有生命周期感知能力,确保界面符合数据状态,不会发生内存泄露,不会因 Ac

    手写消息总线LiveDataBus,让你永无后顾之忧

    Android_SE的博客

    07-19 356

    做了很久的面试专题,不知道对各位需要面试和有跳槽想法的小伙伴有没有帮助,今天收集一篇关于LiveDataBus方面的文章,面试方面的收集,后续我还会持续更新如果觉得有用可以点个关注 Android四大组件和线程间通信方式有很多,比如Handler管道、广播、接口回调、rxBus、EventBus等,但是这些方式都存在一些瑕疵,(比如EvebtBus可能现在用的人比较少了,个人见解可以能算半个过...

    LiveDataBus-Android消息总线,基于LiveData,具有生命周期感知能力.zip

    09-24

    Android消息总线,基于LiveData,具有生命周期感知能力使用方法Fork本项目或者直接拷贝源码:LiveDataBus.java依赖依赖Android Architecture Compon

    Android面试专题系列(四):Activity之间如何进行通信→LiveDataBus

    cjm2484836553的博客

    03-27 326

    不诗意的女程序媛不是好厨师~ 转载请注明出处,From李诗雨—https://blog.csdn.net/cjm2484836553/article/details/105147592 《Android面试专题系列四》Activity之间如何进行通信→LiveDataBus【先描述一下上面的demo】【代码实现】【使用说明】【分析原理】【小结】 现在当面试官问你:“Activity之间如何进行...

    Android消息总线LiveDataBus

    带着键盘走江湖。。。

    07-05 274

    Android消息总线LiveDataBus Android 的生命周期比较复杂,一般情况下只能覆写 Activity / Fragment 的回调方法(onCreate、onResume、onPause、onStop、onDestroy 等)才能监听生命周期,样板代码少不了,可维护性也较差。 Google 为了帮助 Android 开发者更快更好地开发 App,推出了一系列组件,这些组件被打包成...

    LiveDataBus详解

    听海的博客

    07-05 3704

    1、 path是系统用来指定可执行文件的完整路径,即使不在path中设置JDK的路径也可执行Java文件,但必须把完整的路径写出来,如C:\Program Files\Java\jdk1.6.0_10\bin\javac TheClass.java。path是用来搜索所执行的可执行文件路径的,如果执行的可执行文件不在当前目录下,那就会依次搜索path中设置的路径;而java的各种操作命令是在其安装...

    手写消息总线LiveDataBus

    weixin_34355881的博客

    01-28 83

    Android四大组件和线程间通信方式有很多,比如Handler管道、广播、接口回调、rxBus、EventBus等,但是这些方式都存在一些瑕疵,具体的优缺点如下:那么有没有一种通信方式可以集以上所有框架的优点于一身,并且避免以上缺点呢?答案就是作者今天要分享的livedatabus,livedatabus是基于原生的livedata实现的通信框架,它拥有以下的优点:首先我们来看一下LiveDat...

    LiveDataBus使用方式

    博客

    08-23 3663

    调用方式 订阅消息 observe 生命周期感知,不需要手动取消订阅 LiveDataBus.get() .with("key_name", String.class) .observe(this, new Observer<String>() { @Override public void onChanged(@Nul...

    LiveDataBus---一个智能优雅的组件间通信工具

    xiyangyang8110的博客

    05-05 563

    LiveDataBus具有智能感知组件生命周期的功能,不需要像EventBus那样需要反注册操作,能够有效防止内存泄漏,LiveData是一个可以被观察的数据持有类,是LiveDataBus的核心,已经实现了大部分操作。 https://www.cnblogs.com/meituantech/p/9376449.html#undefined ...

    事件总线LiveDataBus

    mingyunxiaohai的专栏

    04-27 583

    最近在使用谷歌官方的架构组件重构项目,在事件总线的选择方面,以前用的是EventBus,因为现在项目中使用了LiveData,想到了之前看过的美团的一篇文章Android消息总线的演进之路里面讲了使用LiveDataBus,来代替RxBus、EventBus。感觉想法非常好,于是项目中开始使用LiveDataBus,使用是非常简单的,不过来需了解实现原理。 开始之前最好先了解一下LiveData可...

    ©️2020 CSDN 皮肤主题: 游动-白 设计师:上身试试 返回首页

    luo_boke CSDN认证博客专家 CSDN认证企业博客

    码龄5年 暂无认证

    71 原创1万+ 周排名6万+ 总排名


    签到新秀

    持之以恒

    勤写标兵Lv3

    学习力

    原力新人

    私信

    关注

    热门文章


    • Neither BindingResult nor plain target object for bean name 'command' available as request attribute 10644
    • Android Studio 4.0新特性及升级异常 10433
    • Entry name *.xml collided终极解决方案 10322
    • Android CameraX 使用入门 4854
    • Android Studio update失败问题 some conflicts were found in the installation area 4832


    分类专栏


    • Android技术框架 2篇
    • 开发工具 7篇
    • 常规基础篇 22篇
    • 十万个为什么? 1篇
    • Android基础篇 25篇
    • Android技术篇 15篇
    • Java技术篇 6篇
    • Android异常解决篇 11篇
    • Java异常解决篇


    最新评论


    • Android Room数据库,用过你才知道好

      weixin_41768597: 有个问题,增删改查之后,都存在wal文件中了,不知道什么时候才会放到db中,这个了解吗表情包

    • Android Studio 4.0.+NDK项目开发详细教学

      luo_boke: 现在build 是4.1.1 gradle是6.5

    • Android Studio 4.0.+NDK项目开发详细教学

      luo_boke: 更新到最新下就可以了

    • Android Studio 4.0.+NDK项目开发详细教学

      西红柿超级无敌好吃: 你好,请问一下,为什么你的cmake Version可以使用3.6.0呀,我as版本4.0.1,一直提示3.10.2是最低使用版本[code=java] Actual CMake version '3.6.0' did not satisfy requested minimum or default CMake minimum version '3.10.2'. Possibly cmake.dir doesn't match android.externalNativeBuild.cmake.version. [/code]

    • 2020 Android studio 最全必用插件

      luo_boke: 还行吧,主要是用来发现括号对称关系的


    最新文章


    • LiveData深入浅出原理分析
    • Android studio 4.1 新特性及升级异常
    • Android Binder通信原理详解


    2021年2篇

    2020年57篇

    2019年15篇

    2017年1篇

    2016年1篇

    2015年3篇

    目录

    目录

    分类专栏


    • Android技术框架 2篇
    • 开发工具 7篇
    • 常规基础篇 22篇
    • 十万个为什么? 1篇
    • Android基础篇 25篇
    • Android技术篇 15篇
    • Java技术篇 6篇
    • Android异常解决篇 11篇
    • Java异常解决篇



     附件

    附件类型

    PNGPNG

    历史版本-目录  [回到顶端]
      知识分享平台 -V 4.8.7 -wcp