LiveData 是 Android Architecture Components 提供的一个可观察的数据持有者类,具有以下特点:
java// 可以修改数据
private final MutableLiveData<List<DataFileItem>> _currentDataFiles
= new MutableLiveData<>();
// 可以调用 setValue() 和 postValue()
_currentDataFiles.setValue(dataList); // 主线程
_currentDataFiles.postValue(dataList); // 任意线程
java// 只读,不能修改
public LiveData<List<DataFileItem>> currentDataFiles = _currentDataFiles;
// 只能观察,不能修改
viewModel.currentDataFiles.observe(this, data -> {
// 观察数据变化
});
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;
}
}
设计优势:
java// 必须在主线程调用
_currentDataFiles.setValue(dataList);
使用场景:
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);
}
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);
}
});
}
java// 获取当前值(可能为 null)
List<DataFileItem> currentData = viewModel.getCurrentDataFiles().getValue();
// 项目中的使用
public List<DataFileItem> getAllFailedRecords() {
List<DataFileItem> dataFiles = getCurrentDataFiles().getValue();
if (dataFiles == null) {
return new ArrayList<>();
}
// 处理数据...
}
注意:
getValue() 可能返回 nulljava// 当 Activity/Fragment 处于活跃状态时,观察者才会收到通知
viewModel.getCurrentDataFiles().observe(lifecycleOwner, data -> {
// 只有当 lifecycleOwner 处于 STARTED 或 RESUMED 状态时
// 才会收到数据更新
});
java// 当 Activity/Fragment 销毁时,LiveData 自动取消观察
// 不需要手动调用 removeObserver()
// 避免内存泄漏
Activity/Fragment 生命周期状态: - CREATED:已创建但未启动 - STARTED:已启动(可见但不在前台) - RESUMED:已恢复(可见且在前台) - DESTROYED:已销毁 LiveData 只在 STARTED 和 RESUMED 状态时通知观察者
项目中的体现:
java// TestCaseListFragment.java
// 使用 getViewLifecycleOwner() 确保与 Fragment 的 View 生命周期绑定
viewModel.getCurrentDataFiles().observe(
getViewLifecycleOwner(), // 当 Fragment View 销毁时自动取消观察
dataFiles -> {
// 更新 UI
}
);
java// MainActivity.java
viewModel.load("remote"); // 请求加载数据
java// DataFileViewModel.java
@Override
public void onDataFileListUpdate(List<DataFileItem> dataFileList) {
// Model 层回调,更新 LiveData
_currentDataFiles.postValue(dataFileList); // 触发观察者
loading.postValue(false); // 隐藏加载状态
}
java// TestCaseListFragment.java
// 观察者自动被触发(因为数据变化了)
viewModel.getCurrentDataFiles().observe(
getViewLifecycleOwner(),
dataFiles -> {
// 这里自动执行
adapter.updateData(dataFiles); // 更新列表
updateStatistics(dataFiles); // 更新统计
}
);
数据流图:
Model 层数据更新 ↓ ViewModel.postValue() ← 更新 LiveData ↓ 触发所有观察者 ↓ View 的 Observer 回调 ← 自动执行 ↓ 更新 UI
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);
});
}
}
java// Activity 旋转时:
// 1. Activity 被销毁并重建
// 2. ViewModel 保留(不重建)
// 3. LiveData 保留数据
// 4. 新的 Activity 重新观察,立即收到最新数据
// 5. 不需要重新加载数据
java// 可以在后台线程更新
new Thread(() -> {
List<DataFileItem> data = loadFromNetwork();
// 安全地在后台线程更新
_currentDataFiles.postValue(data);
}).start();
// LiveData 会自动切换到主线程通知观察者
java// 多个观察者观察同一个 LiveData
viewModel.getCurrentDataFiles().observe(fragment1, data -> { /* ... */ });
viewModel.getCurrentDataFiles().observe(fragment2, data -> { /* ... */ });
viewModel.getCurrentDataFiles().observe(activity, data -> { /* ... */ });
// 当数据更新时,所有观察者都会收到相同的值
// 保证数据一致性
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<>();
}
java// MainActivity.java - 观察任务信息
viewModel.getTaskInfo().observe(this, taskInfo -> {
mTitleTaskNameTextView.setText(taskInfo.getName());
});
// TestCaseListFragment.java - 观察数据文件列表
viewModel.getCurrentDataFiles().observe(
getViewLifecycleOwner(),
dataFiles -> {
adapter.updateData(dataFiles);
}
);
// 同一个 ViewModel,多个观察者,数据同步更新
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);
}
}
java// ✅ 推荐:私有 MutableLiveData + 公开 LiveData
private final MutableLiveData<String> _name = new MutableLiveData<>();
public LiveData<String> getName() {
return _name;
}
// 或者直接暴露
public LiveData<String> name = _name;
java// 方式 1: 使用 setValue() 初始化
private final MutableLiveData<Boolean> loading = new MutableLiveData<>();
loading.setValue(false); // 初始化
// 方式 2: 使用构造函数
private final MutableLiveData<Boolean> loading = new MutableLiveData<>(false);
javapublic void updateData(List<DataFileItem> newData) {
List<DataFileItem> current = _currentDataFiles.getValue();
// 只有当数据真正变化时才更新
if (!Objects.equals(current, newData)) {
_currentDataFiles.postValue(newData);
}
}
java// 使用 MediatorLiveData 组合多个 LiveData
MediatorLiveData<Boolean> allDataLoaded = new MediatorLiveData<>();
allDataLoaded.addSource(taskInfo, value -> checkAllLoaded());
allDataLoaded.addSource(currentDataFiles, value -> checkAllLoaded());
java// 网络请求回调(后台线程)
@Override
public void onDataFileListUpdate(List<DataFileItem> dataFileList) {
_currentDataFiles.postValue(dataFileList); // ✅ 正确
}
javanew Thread(() -> {
_currentDataFiles.setValue(data); // ❌ 错误!会崩溃
}).start();
java// Fragment 中
viewModel.getData().observe(getViewLifecycleOwner(), data -> {
// ✅ 正确:与 Fragment View 生命周期绑定
});
java// Fragment 中
viewModel.getData().observe(this, data -> {
// ❌ 可能有问题:与 Fragment 生命周期绑定,而不是 View
});
javaviewModel.getCurrentDataFiles().observe(this, dataFiles -> {
if (dataFiles != null) { // ✅ 检查 null
adapter.updateData(dataFiles);
}
});
javaviewModel.getData().observe(this, data -> {
// ✅ 正确:只更新 UI
updateUI(data);
// ❌ 错误:不要在观察者中执行耗时操作
// loadMoreData(); // 可能导致死循环
});
| 特性 | LiveData | RxJava Observable |
|---|---|---|
| 生命周期感知 | ✅ 自动 | ❌ 需要手动管理 |
| 学习曲线 | 简单 | 较复杂 |
| 功能丰富度 | 基础 | 非常丰富 |
| 适用场景 | Android UI 数据绑定 | 复杂的数据流处理 |
| 特性 | LiveData | EventBus |
|---|---|---|
| 类型安全 | ✅ 编译时检查 | ❌ 运行时检查 |
| 生命周期感知 | ✅ 自动 | ❌ 需要手动管理 |
| 数据持有 | ✅ 持有最新值 | ❌ 不持有数据 |
| 使用场景 | ViewModel 到 View | 全局事件通知 |
java// 私有可变
private final MutableLiveData<List<DataFileItem>> _currentDataFiles
= new MutableLiveData<>();
// 公开只读
public LiveData<List<DataFileItem>> currentDataFiles = _currentDataFiles;
// 更新数据(可能在后台线程)
_currentDataFiles.postValue(dataList);
java// 观察数据变化
viewModel.getCurrentDataFiles().observe(
getViewLifecycleOwner(),
dataFiles -> {
// 数据变化时自动执行
adapter.updateData(dataFiles);
}
);
本文作者:lixf6
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!