LiveData 一般是和 ViewModel 结合起来使用的,比如计数器功能,在单线程模式下确实可以正常工作,但如果在 ViewModel 的内部开启了线程去执行一些耗时逻辑,那么在点击按钮后就我们想立即去获取最新的数据,但是得到的肯定还是之前的旧数据。
**原本我们一直使用的都是在 Activity 中手动的获取 ViewModel 中的数据这种交互方式,但是 ViewModel 却无法将数据的变化主动地通知给 Activity。**那么怎么实现主动通知呢?或许你会说将 Activity 的实例传给 ViewModel,这样 ViewModel 不就能主动通知 Activity 了吗?很可惜,这是错误的。因为 ViewModel 的生命周期是长于 Activity,如果这样做了,那么可能因为 Activity 无法释放而造成内存泄漏。
LiveData 可以轻松地解决这个问题。LiveData 可以包含任何类型的数据,并在数据发生变化的时候通知给观察者。也就是说,我们可以将数据使用 LiveData 来包装,然后在 Activity 中去观察它,就可以将数据变化通知给 Activity。
使用示例:这里和 ViewModel 结合使用
- 创建 ViewModel 将里面的数据用 LiveData 包装起来
public class MyViewModel extends ViewModel {
public MyViewModel(int countReserved) {
this._counter.setValue(countReserved);
}
// LiveData 是不可变的
// 我们给 _counter 加上 private 修饰符,这样 _counter 外部就不可见了。
// 然后我们定义不可变的 counter 变量,并让它的 getValue() 方法返回 _counter 中的数据。
// 这样,当外部调用 counter 变量时,其实获取到的是 _counter 的值,
// 但是无法给 _counter 设置数据,从而保证了ViewModel 的数据封装性
public LiveData<Integer> counter = new LiveData<Integer>() {
@Override
public Integer getValue() {
return _counter.getValue();
}
};
// MutableLiveData 是一种可变的 LiveData
private MutableLiveData<Integer> _counter = new MutableLiveData<Integer>();
public void plus() {
int value = counter.getValue() == null ? 0 : counter.getValue()+1;
_counter.setValue(value);
}
public void clear() {
_counter.setValue(0);
}
}
主要有三种读写数据的方法,分别是 getValue()、setValue() 和 postValue() 方法。setValue() 只能在主线程中使用,postValue() 可以用于非主线程中使用。
- 通过viewModel.counter 的 observe() 方法来观察数据的变化:
viewModel1 = new ViewModelProvider(this, new ViewModelProvider.Factory() {
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
return (T) new com.example.androidjetpack.LiveData.MyViewModel(countReserved);
}
}).get(com.example.androidjetpack.LiveData.MyViewModel.class);
plusButton.setOnClickListener(view -> viewModel1.plus());
clearButton.setOnClickListener(view -> viewModel1.clear());
// 当 counter 中包含的数据发生变化时就会回调到这里
viewModel1.counter.observe(this, new Observer<Integer>() {
@Override
public void onChanged(Integer integer) {
String text = viewModel1.counter.getValue()==null ? \"\" :
viewModel1.counter.getValue().toString();
infoText.setText(text);
}
});
请登录后查看评论内容