编辑
2026-01-06
移动端
00

目录

LiveData 详解
一、LiveData 是什么?
二、LiveData vs MutableLiveData
1. MutableLiveData(可变)
2. LiveData(只读)
3. 项目中的使用模式
三、LiveData 的核心方法
1. 更新数据的方法
setValue() - 主线程更新
postValue() - 任意线程更新
2. 观察数据的方法
observe() - 观察数据变化
3. 获取当前值的方法
getValue() - 获取当前值
四、LiveData 的生命周期感知
1. 自动管理观察者
2. 自动取消观察
3. 生命周期状态
五、完整的数据流示例
场景:加载测试数据文件列表
步骤 1: View 请求数据
步骤 2: ViewModel 更新 LiveData
步骤 3: View 自动更新 UI
六、LiveData 的优势
1. 避免内存泄漏
2. 自动处理配置变更
3. 线程安全
4. 数据一致性
七、项目中的实际应用
1. 多个 LiveData 管理不同状态
2. 在多个地方观察同一个 LiveData
3. 更新单个数据项
八、常见使用模式
1. 封装模式(推荐)
2. 初始化默认值
3. 条件更新
4. 组合多个 LiveData
九、注意事项和最佳实践
1. ✅ 正确:使用 postValue() 在后台线程更新
2. ❌ 错误:在后台线程使用 setValue()
3. ✅ 正确:使用 getViewLifecycleOwner() 在 Fragment 中
4. ❌ 错误:在 Fragment 中使用 this
5. ✅ 正确:检查 null 值
6. ✅ 正确:避免在观察者中执行耗时操作
十、LiveData 与其他技术的对比
LiveData vs RxJava Observable
LiveData vs EventBus
十一、总结
LiveData 的核心价值:
在你的项目中的作用:
关键要点:
十二、实际代码示例总结
ViewModel 中定义:
View 中观察:

LiveData 详解

一、LiveData 是什么?

LiveData 是 Android Architecture Components 提供的一个可观察的数据持有者类,具有以下特点:

  1. 生命周期感知:自动感知 Activity/Fragment 的生命周期
  2. 数据变化通知:数据变化时自动通知观察者
  3. 避免内存泄漏:当观察者(Activity/Fragment)销毁时自动取消观察
  4. 线程安全:支持后台线程更新数据

二、LiveData vs MutableLiveData

1. MutableLiveData(可变)

java
// 可以修改数据 private final MutableLiveData<List<DataFileItem>> _currentDataFiles = new MutableLiveData<>(); // 可以调用 setValue() 和 postValue() _currentDataFiles.setValue(dataList); // 主线程 _currentDataFiles.postValue(dataList); // 任意线程

2. LiveData(只读)

java
// 只读,不能修改 public LiveData<List<DataFileItem>> currentDataFiles = _currentDataFiles; // 只能观察,不能修改 viewModel.currentDataFiles.observe(this, data -> { // 观察数据变化 });

3. 项目中的使用模式

java
// DataFileViewModel.java public class DataFileViewModel extends ViewModel { // 私有:可变的,用于内部修改 private final MutableLiveData<List<DataFileItem>> _currentDataFiles = new MutableLiveData<>(); // 公开:只读的,供外部观察 public LiveData<List<DataFileItem>> currentDataFiles = _currentDataFiles; // 或者通过 getter 方法暴露 public LiveData<List<DataFileItem>> getCurrentDataFiles() { return currentDataFiles; } }

设计优势

  • ✅ 封装性:外部无法直接修改数据
  • ✅ 安全性:只能通过 ViewModel 的方法更新数据
  • ✅ 符合 MVVM 架构原则

三、LiveData 的核心方法

1. 更新数据的方法

setValue() - 主线程更新

java
// 必须在主线程调用 _currentDataFiles.setValue(dataList);

使用场景

  • 在主线程中更新数据
  • 同步更新,立即生效

postValue() - 任意线程更新

java
// 可以在任意线程调用(后台线程、网络回调等) _currentDataFiles.postValue(dataList);

使用场景

  • 在后台线程更新数据(网络请求回调、数据库查询等)
  • 异步更新,会切换到主线程通知观察者

项目中的实际使用

java
// DataFileViewModel.java @Override public void onDataFileListUpdate(List<DataFileItem> dataFileList) { // 这个方法可能在后台线程被调用(网络请求回调) // 所以使用 postValue() 而不是 setValue() _currentDataFiles.postValue(dataFileList); loading.postValue(false); } @Override public void onTaskInfoUpdate(TestTaskBean taskInfo) { // 同样使用 postValue(),因为可能来自后台线程 _taskInfo.postValue(taskInfo); }

2. 观察数据的方法

observe() - 观察数据变化

java
// 基本用法 viewModel.getCurrentDataFiles().observe( lifecycleOwner, // 生命周期所有者 dataFiles -> { // 观察者回调 // 数据变化时自动执行 adapter.updateData(dataFiles); } );

参数说明

  • lifecycleOwner:生命周期所有者(Activity/Fragment)
  • Observer:数据变化时的回调

项目中的实际使用

java
// TestCaseListFragment.java @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); // 观察数据文件列表 viewModel.getCurrentDataFiles().observe( getViewLifecycleOwner(), // Fragment 使用 getViewLifecycleOwner() dataFiles -> { if (dataFiles != null) { adapter.updateData(dataFiles); updateStatistics(dataFiles); } } ); // 观察正在执行的文件 viewModel.getExecutingDataFile().observe( getViewLifecycleOwner(), script -> { if (script != null) { int position = adapter.getDataFiles().indexOf(script); if (position != -1) { adapter.notifyItemChanged(position); } } } ); } // MainActivity.java @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Activity 使用 this 作为 lifecycleOwner viewModel.getTaskInfo().observe(this, taskInfo -> { if (taskInfo != null) { mTitleTaskNameTextView.setText(taskInfo.getName()); } }); viewModel.getLoading().observe(this, this::showLoading); viewModel.getErrorCode().observe(this, errorCode -> { if (errorCode != null) { mErrorTextView.setText(errorCode.getMessageRes()); mErrorContainer.setVisibility(View.VISIBLE); } else { mErrorContainer.setVisibility(View.GONE); } }); }

3. 获取当前值的方法

getValue() - 获取当前值

java
// 获取当前值(可能为 null) List<DataFileItem> currentData = viewModel.getCurrentDataFiles().getValue(); // 项目中的使用 public List<DataFileItem> getAllFailedRecords() { List<DataFileItem> dataFiles = getCurrentDataFiles().getValue(); if (dataFiles == null) { return new ArrayList<>(); } // 处理数据... }

注意

  • getValue() 可能返回 null
  • 必须在主线程调用
  • 只获取当前值,不会触发观察者

四、LiveData 的生命周期感知

1. 自动管理观察者

java
// 当 Activity/Fragment 处于活跃状态时,观察者才会收到通知 viewModel.getCurrentDataFiles().observe(lifecycleOwner, data -> { // 只有当 lifecycleOwner 处于 STARTED 或 RESUMED 状态时 // 才会收到数据更新 });

2. 自动取消观察

java
// 当 Activity/Fragment 销毁时,LiveData 自动取消观察 // 不需要手动调用 removeObserver() // 避免内存泄漏

3. 生命周期状态

Activity/Fragment 生命周期状态: - CREATED:已创建但未启动 - STARTED:已启动(可见但不在前台) - RESUMED:已恢复(可见且在前台) - DESTROYED:已销毁 LiveData 只在 STARTED 和 RESUMED 状态时通知观察者

项目中的体现

java
// TestCaseListFragment.java // 使用 getViewLifecycleOwner() 确保与 Fragment 的 View 生命周期绑定 viewModel.getCurrentDataFiles().observe( getViewLifecycleOwner(), // 当 Fragment View 销毁时自动取消观察 dataFiles -> { // 更新 UI } );

五、完整的数据流示例

场景:加载测试数据文件列表

步骤 1: View 请求数据

java
// MainActivity.java viewModel.load("remote"); // 请求加载数据

步骤 2: ViewModel 更新 LiveData

java
// DataFileViewModel.java @Override public void onDataFileListUpdate(List<DataFileItem> dataFileList) { // Model 层回调,更新 LiveData _currentDataFiles.postValue(dataFileList); // 触发观察者 loading.postValue(false); // 隐藏加载状态 }

步骤 3: View 自动更新 UI

java
// TestCaseListFragment.java // 观察者自动被触发(因为数据变化了) viewModel.getCurrentDataFiles().observe( getViewLifecycleOwner(), dataFiles -> { // 这里自动执行 adapter.updateData(dataFiles); // 更新列表 updateStatistics(dataFiles); // 更新统计 } );

数据流图

Model 层数据更新 ↓ ViewModel.postValue() ← 更新 LiveData ↓ 触发所有观察者 ↓ View 的 Observer 回调 ← 自动执行 ↓ 更新 UI

六、LiveData 的优势

1. 避免内存泄漏

java
// ❌ 传统方式(可能泄漏) public class MyActivity extends Activity { private Handler handler = new Handler(); private void loadData() { api.getData(new Callback() { @Override public void onSuccess(Data data) { // 如果 Activity 已销毁,这里可能崩溃 updateUI(data); } }); } } // ✅ 使用 LiveData(自动处理) public class MyActivity extends Activity { private void observeData() { viewModel.getData().observe(this, data -> { // Activity 销毁时自动取消观察,不会泄漏 updateUI(data); }); } }

2. 自动处理配置变更

java
// Activity 旋转时: // 1. Activity 被销毁并重建 // 2. ViewModel 保留(不重建) // 3. LiveData 保留数据 // 4. 新的 Activity 重新观察,立即收到最新数据 // 5. 不需要重新加载数据

3. 线程安全

java
// 可以在后台线程更新 new Thread(() -> { List<DataFileItem> data = loadFromNetwork(); // 安全地在后台线程更新 _currentDataFiles.postValue(data); }).start(); // LiveData 会自动切换到主线程通知观察者

4. 数据一致性

java
// 多个观察者观察同一个 LiveData viewModel.getCurrentDataFiles().observe(fragment1, data -> { /* ... */ }); viewModel.getCurrentDataFiles().observe(fragment2, data -> { /* ... */ }); viewModel.getCurrentDataFiles().observe(activity, data -> { /* ... */ }); // 当数据更新时,所有观察者都会收到相同的值 // 保证数据一致性

七、项目中的实际应用

1. 多个 LiveData 管理不同状态

java
// DataFileViewModel.java public class DataFileViewModel extends ViewModel { // 数据 private final MutableLiveData<List<DataFileItem>> _currentDataFiles = new MutableLiveData<>(); public LiveData<List<DataFileItem>> currentDataFiles = _currentDataFiles; // 任务信息 private final MutableLiveData<TestTaskBean> _taskInfo = new MutableLiveData<>(); public LiveData<TestTaskBean> taskInfo = _taskInfo; // 正在执行的文件 private final MutableLiveData<DataFileItem> _executingDataFile = new MutableLiveData<>(); public LiveData<DataFileItem> executingDataFile = _executingDataFile; // UI 状态 private final MutableLiveData<Boolean> loading = new MutableLiveData<>(); private final MutableLiveData<ErrorCode> errorCode = new MutableLiveData<>(); // 测试结果 private final MutableLiveData<TestResultEntity> latestResult = new MutableLiveData<>(); }

2. 在多个地方观察同一个 LiveData

java
// MainActivity.java - 观察任务信息 viewModel.getTaskInfo().observe(this, taskInfo -> { mTitleTaskNameTextView.setText(taskInfo.getName()); }); // TestCaseListFragment.java - 观察数据文件列表 viewModel.getCurrentDataFiles().observe( getViewLifecycleOwner(), dataFiles -> { adapter.updateData(dataFiles); } ); // 同一个 ViewModel,多个观察者,数据同步更新

3. 更新单个数据项

java
// DataFileViewModel.java public void updateScriptResult(DataFileItem updatedItem) { // 获取当前列表 List<DataFileItem> currentList = new ArrayList<>( Objects.requireNonNull(_currentDataFiles.getValue()) ); // 查找并更新 int index = currentList.indexOf(updatedItem); if (index != -1) { currentList.set(index, updatedItem); // 更新整个列表,触发观察者 _currentDataFiles.postValue(currentList); } }

八、常见使用模式

1. 封装模式(推荐)

java
// ✅ 推荐:私有 MutableLiveData + 公开 LiveData private final MutableLiveData<String> _name = new MutableLiveData<>(); public LiveData<String> getName() { return _name; } // 或者直接暴露 public LiveData<String> name = _name;

2. 初始化默认值

java
// 方式 1: 使用 setValue() 初始化 private final MutableLiveData<Boolean> loading = new MutableLiveData<>(); loading.setValue(false); // 初始化 // 方式 2: 使用构造函数 private final MutableLiveData<Boolean> loading = new MutableLiveData<>(false);

3. 条件更新

java
public void updateData(List<DataFileItem> newData) { List<DataFileItem> current = _currentDataFiles.getValue(); // 只有当数据真正变化时才更新 if (!Objects.equals(current, newData)) { _currentDataFiles.postValue(newData); } }

4. 组合多个 LiveData

java
// 使用 MediatorLiveData 组合多个 LiveData MediatorLiveData<Boolean> allDataLoaded = new MediatorLiveData<>(); allDataLoaded.addSource(taskInfo, value -> checkAllLoaded()); allDataLoaded.addSource(currentDataFiles, value -> checkAllLoaded());

九、注意事项和最佳实践

1. ✅ 正确:使用 postValue() 在后台线程更新

java
// 网络请求回调(后台线程) @Override public void onDataFileListUpdate(List<DataFileItem> dataFileList) { _currentDataFiles.postValue(dataFileList); // ✅ 正确 }

2. ❌ 错误:在后台线程使用 setValue()

java
new Thread(() -> { _currentDataFiles.setValue(data); // ❌ 错误!会崩溃 }).start();

3. ✅ 正确:使用 getViewLifecycleOwner() 在 Fragment 中

java
// Fragment 中 viewModel.getData().observe(getViewLifecycleOwner(), data -> { // ✅ 正确:与 Fragment View 生命周期绑定 });

4. ❌ 错误:在 Fragment 中使用 this

java
// Fragment 中 viewModel.getData().observe(this, data -> { // ❌ 可能有问题:与 Fragment 生命周期绑定,而不是 View });

5. ✅ 正确:检查 null 值

java
viewModel.getCurrentDataFiles().observe(this, dataFiles -> { if (dataFiles != null) { // ✅ 检查 null adapter.updateData(dataFiles); } });

6. ✅ 正确:避免在观察者中执行耗时操作

java
viewModel.getData().observe(this, data -> { // ✅ 正确:只更新 UI updateUI(data); // ❌ 错误:不要在观察者中执行耗时操作 // loadMoreData(); // 可能导致死循环 });

十、LiveData 与其他技术的对比

LiveData vs RxJava Observable

特性LiveDataRxJava Observable
生命周期感知✅ 自动❌ 需要手动管理
学习曲线简单较复杂
功能丰富度基础非常丰富
适用场景Android UI 数据绑定复杂的数据流处理

LiveData vs EventBus

特性LiveDataEventBus
类型安全✅ 编译时检查❌ 运行时检查
生命周期感知✅ 自动❌ 需要手动管理
数据持有✅ 持有最新值❌ 不持有数据
使用场景ViewModel 到 View全局事件通知

十一、总结

LiveData 的核心价值:

  1. 生命周期感知:自动管理观察者,避免内存泄漏
  2. 响应式更新:数据变化时自动通知 UI
  3. 线程安全:支持后台线程更新数据
  4. 配置变更友好:Activity 重建时保留数据
  5. 简单易用:API 简洁,学习成本低

在你的项目中的作用:

  • ✅ 实现 MVVM 架构的数据绑定
  • ✅ 自动更新 UI(列表、统计、状态等)
  • ✅ 管理多个 UI 状态(加载、错误、执行中等)
  • ✅ 避免内存泄漏和崩溃
  • ✅ 简化异步数据更新流程

关键要点:

  1. MutableLiveData 用于内部修改,LiveData 用于外部观察
  2. postValue() 用于后台线程,setValue() 用于主线程
  3. observe() 时使用正确的 lifecycleOwner
  4. 在观察者中只做 UI 更新,不做耗时操作
  5. 合理使用多个 LiveData 管理不同状态

十二、实际代码示例总结

ViewModel 中定义:

java
// 私有可变 private final MutableLiveData<List<DataFileItem>> _currentDataFiles = new MutableLiveData<>(); // 公开只读 public LiveData<List<DataFileItem>> currentDataFiles = _currentDataFiles; // 更新数据(可能在后台线程) _currentDataFiles.postValue(dataList);

View 中观察:

java
// 观察数据变化 viewModel.getCurrentDataFiles().observe( getViewLifecycleOwner(), dataFiles -> { // 数据变化时自动执行 adapter.updateData(dataFiles); } );

本文作者:lixf6

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!