当前位置: 首页 > news >正文

记录LiveData使用及原理

LiveData

一 使用方式:

添加依赖

implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.7.0"

创建LiveData

val liveData = MutableLiveData<String>()

观察数据变化

liveData.observe(this) { data ->// 这里是数据变化时的回调(this 通常是 LifecycleOwner,如 Activity/Fragment)textView.text = data
}

更新数据

liveData.value = "新数据"           // 主线程
liveData.postValue("异步新数据")    // 任何线程

典型场景就是和ViewModel结合,做数据驱动界面更新。

二 LiveData原理讲解

1.生命周期感知

LiveData 通过感知 LifecycleOwner(Activity、Fragment)的生命周期,只在 owner 处于活跃状态(如 STARTED/RESUMED)时分发数据变更,owner 销毁后自动移除监听,避免内存泄漏。

2. 观察者模式

LiveData 内部维护一个 Observer 列表。当数据变化时(setValue/postValue),遍历所有活跃 Observer,回调其 onChanged 方法。

3. 数据分发机制

  • 只有处于活跃生命周期的 Observer 才会收到数据
  • 数据在主线程分发(postValue 会切到主线程)

4. 自动解绑

当 LifecycleOwner 进入 DESTROYED 状态,LiveData 自动移除对应的 Observer,无需手动解绑。

5. 粘性事件

新注册的 Observer,如果 LiveData 已有数据,会立即收到最新数据一次(即粘性事件)。

这个就更没啥说的了,就是一个观察者模式的应用,并且感知宿主也就是LifecycleOwner的生命周期,仅在活跃的时候进行数据分发。在宿主销毁的时候自动解绑。

ViewModel

创建ViewModel

public class MyViewModel extends ViewModel {private MutableLiveData<String> userName = new MutableLiveData<>();public LiveData<String> getUserName() {return userName;}public void setUserName(String name) {userName.setValue(name);}
}

在界面中获取ViewModel

public class MainActivity extends AppCompatActivity {private MyViewModel viewModel;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 获取 ViewModel 实例,生命周期与 Activity 相关联viewModel = new ViewModelProvider(this).get(MyViewModel.class);// LiveData 绑定 UI,自动感知生命周期viewModel.getUserName().observe(this, new Observer<String>() {@Overridepublic void onChanged(String name) {TextView textView = findViewById(R.id.textView);textView.setText(name);}});// 更新数据(如点击按钮)viewModel.setUserName("Copilot");}
}

二:ViewModel原理简述

viewModel与Activity生命周期绑定,但是不会因为界面重建而销毁,只有界面彻底销毁时才会销毁。它不持有activity的直接引用,值存储数据,降低内存泄漏的风险。

不想写了,真的不清楚写啥~ 能想到面试官问

为什么我们总是使用viewModel搭配LiveData使用?

因为它内置了 MutableLiveData 我们用LiveData保存数据,而viewModel在界面重建的时候不会销毁。而LiveData又可以感知生命周期,巴拉巴拉 扒拉扒拉  自己遍吧。他们就是很配,那有什么 为什么~ 

哦,对哦。有一个现实问题;

比如你的ViewModel 是绑定的Activity创建的,而你在Fragment上使用,会发现使用MutableLiveData 变更数据的时候又多次通知为什么?

这其实是ViewModel的作用域 和 LiveData粘性事件组合导致的。

  • 如果你用 ViewModelProvider(this) 获取 ViewModel,this 是 Activity,则 ViewModel 作用域是整个 Activity。
  • 在 Activity 下的多个 Fragment 中,使用同一个 ViewModel 实例(如 MainViewModel),它们共享数据。
  • LiveData 的 observe() 方法是“粘性”的:新注册的 Observer 会立即收到 LiveData 当前最新数据(即使之前已变化过)。
  • 如果你在 Fragment 的 onCreateView/onViewCreated 每次都 observe,且 Fragment多次重建(如切换Tab或返回栈),每次都会收到最新数据一次。
  • 当你调用 setValue 或 postValue,所有活跃 Observer(无论在 Activity 还是 Fragment)都会收到数据变化通知。

这其实是我搭建矿建的时候埋的一个坑,当时在BaseFragment中获取ViewModel的作用域是Fragment,但是我们有一个问我有什么方式可以优雅的Fragment之间传值吗?我当时脑子一热就直接把作用域改成了Activity,这样ViewModel作用域就是Activity,它持有的所有Fragment都可以互相传值。但是问题就是会触发多次。

解决办法是 魔改LiveData,消除粘性事件。比如  SingleLiveEvent

public class SingleLiveEvent <T> extends MutableLiveData<T> {private final AtomicBoolean mPending = new AtomicBoolean(false);@Overridepublic void observe(@NonNull LifecycleOwner owner, @NonNull final Observer<? super T> observer) {super.observe(owner, new Observer<T>() {@Overridepublic void onChanged(@Nullable T t) {if (mPending.compareAndSet(true, false)) {observer.onChanged(t);}}});}@MainThreadpublic void setValue(@Nullable T t) {mPending.set(true);super.setValue(t);}/*** Used for cases where T is Void, to make calls cleaner.*/@MainThreadpublic void call() {setValue(null);}
}

通过一个标记变量mPending,只有在事件真正变更时才允许

面试官问你,LiveData和EventBus有什么区别 ,怎么选择使用

“LiveData 是 Jetpack 官方响应式数据持有者,能自动感知生命周期,防止内存泄漏,类型安全,适合 UI 层数据绑定。EventBus 是第三方事件总线库,不感知生命周期,需要手动管理注册和解注册,适合全局和组件间事件通信,但易滥用和管理混乱。一般推荐 UI 层用 LiveData,全局事件可选 EventBus,但要注意生命周期和内存管理。

http://www.dtcms.com/a/331945.html

相关文章:

  • Unity宝箱随机事件实现指南
  • AI三国杀:马斯克炮轰苹果“偏袒”OpenAI,Grok与ChatGPT的应用商店战争揭秘
  • 【昇腾】VirtualBox虚拟机下搭建Ubuntu 22.04环境给TF卡制卡报读写IO错误的问题处理_20250814
  • 【CF】Day127——杂题 (数论 gcd | 数论 gcd | 博弈论 | 二分图判断 | 贪心 + 暴力 / 二分答案 | 数论 gcd + 动态规划)
  • linux 主机驱动(SPI)与外设驱动分离的设计思想
  • 把大模型当“温度计”——基于 LLM 的分布式系统异常根因定位实战
  • 企业可商用的conda:「Miniforge」+「conda-forge」
  • Data Augmentation数据增强
  • 快速部署一个鉴黄服务
  • Android 项目:画图白板APP开发(二)——历史点、数学方式推导点
  • SQL详细语法教程(三)mysql的函数知识
  • 区块链 + 域名Web3时代域名投资的新风口(上)
  • Gemma 3 多模态推理 通过vllm运行Gemma-3-27B-IT模型的推理服务
  • 【系统安装】虚拟机中安装win10IOT企业版系统记录
  • 解决安装 scikit-learn==1.3.1 时出现的版本匹配错误
  • PHP 开发全解析:从基础到实战的进阶之路
  • sFlow原理与配置
  • Java面试场景题大全精简版
  • MySql——聚簇索引(主键索引)和非聚簇索索引(非主键索引)引区别(即聚集索引和非聚集索引区别)
  • MyBatis学习总结(六)
  • 【面板数据】各省及市省级非物质文化遗产数据合集(2005-2024年)
  • 《嵌入式 C 语言编码规范与工程实践个人笔记》参考华为C语言规范标准
  • 解锁 Docker:一场从入门到源码的趣味解谜之旅
  • 卸载python遇到msi文件权限不足
  • Python闭包详解:理解闭包与可变类型和不可变类型的关系
  • 新手如何高效运营亚马逊跨境电商:从传统SP广告到DeepBI智能策略
  • docker 容器管理入门教程
  • 身份全景图
  • Encoder-Decoder Model编码器-解码器模型
  • 【学习笔记】Java并发编程的艺术——第4章 Java并发编程基础