笔者在开发一款即时通讯和音视频应用时,发现需要花费很大的力量去处理系统组件之间的数据传递,稍微有点不注意,就会出现状态错乱不同步的问题,影响用户体验,也给系统稳定性带来了许多挑战。因此,在我们 2.0 版本的重构过程中,毅然决定引入 LiveData,经过实践证明,其是一种优秀的解决方案,很适合处理此类问题,但也有一些细节需要注意,因此有了这篇文章,希望可以记录下来。
1.1 定义
1.2 使用 LiveData 的优势
确保界面符合数据状态
不会发生内存泄漏
不会因 Activity 停止而导致崩溃
不再需要手动处理生命周期
数据始终保持最新状态
适当的配置更改
共享资源
2. 正文
2.1 使用 LiveData 步骤
2.1.1 创建 LiveData 实例以存储某种类型的数据。这通常在 ViewModel 类中完成。
public class NameViewModel extends ViewModel {
// Create a LiveData with a String
private MutableLiveData<String> currentName;
public MutableLiveData<String> getCurrentName() {
if (currentName == null) {
currentName = new MutableLiveData<String>();
}
return currentName;
}
// Rest of the ViewModel...
}
复制代码
2.1.2 创建可定义 onChanged() 方法的 Observer 对象,该方法可以控制当 LiveData 对象存储的数据更改时会发生什么。通常情况下,您可以在界面控制器(如 Activity 或 Fragment)中创建 Observer 对象。使用 observe() 方法将 Observer 对象附加到 LiveData 对象。observe() 方法会采用 LifecycleOwner 对象。这样会使 Observer 对象订阅 LiveData 对象,以使其收到有关更改的通知。通常情况下,您可以在界面控制器(如 Activity 或 Fragment)中附加 Observer 对象
public class NameActivity extends AppCompatActivity {
private NameViewModel model;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Other code to setup the activity...
// Get the ViewModel.
model = new ViewModelProvider(this).get(NameViewModel.class);
// Create the observer which updates the UI.
final Observer<String> nameObserver = new Observer<String>() {
@Override
public void onChanged(@Nullable final String newName) {
// Update the UI, in this case, a TextView.
nameTextView.setText(newName);
}
};
// Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
model.getCurrentName().observe(this, nameObserver);
}
}
复制代码
2.1.3 更新 LiveData 对象,LiveData 没有公开可用的方法来更新存储的数据。MutableLiveData 类将公开 setValue(T) 和 postValue(T) 方法,如果您需要修改存储在 LiveData 对象中的值,则必须使用这些方法。
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String anotherName = "John Doe";
model.getCurrentName().setValue(anotherName);
}
});
复制代码
2.2 LiveData 代码分析
2.2.1 MutableLiveData.java(LiveData 的一个派生类,由于 LiveData 并未提供给外部更新数据的接口,所以一般使用 MutableLiveData 来实例化 LiveData)
package androidx.lifecycle;
/**
* {@link LiveData} which publicly exposes {@link #setValue(T)} and {@link #postValue(T)} method.
*
* @param <T> The type of data hold by this instance
*/
@SuppressWarnings("WeakerAccess")
public class MutableLiveData<T> extends LiveData<T> {
/**
* Creates a MutableLiveData initialized with the given {@code value}.
*
* @param value initial value
*/
public MutableLiveData(T value) {
super(value);
}
/**
* Creates a MutableLiveData with no value assigned to it.
*/
public MutableLiveData() {
super();
}
@Override
public void postValue(T value) {
super.postValue(value);
}
@Override
public void setValue(T value) {
super.setValue(value);
}
}
复制代码
2.2.2 LiveData.observe()方法
@MainThread // 标记该方法只允许在主线程运行,一般是在Activity/Service的onCreate方法中执行
// 第一个参数 LifecycleOwner,表示的是一个具有生命周期的通用组件,如Activity/Service
// 第二个参数 Observer,就是我们的观察者实例,当数据变化时会执行onChange方法
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe"); // 主线程断言检测
if (owner.getLifecycle().getCurrentState() == DESTROYED) { // 如果当前组件的生命周期是销毁,则立即返回
// ignore
return;
}
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer); // 一个用于关联 组件和观察者 之间的对象
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner)) { // 不允许同一个观察者观察不同的组件
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
owner.getLifecycle().addObserver(wrapper); // 添加到组件的观察者队列
}
复制代码
2.2.3 注意事项:
我们看一段注释,如果你已经 post 一个任务给主线程,但还未来得及执行,此时你再多次调用 postValue,则意味着最新的值会被 post,后面的值会覆盖前面的值。这一点需要特别注意,笔者在开发的时候,由于在 Service 中根据网络状态来更新 LiveData 的值,但是发现 Activity 中部分值无法观察到,后来看了注释才焕然大悟。
/**
* Posts a task to a main thread to set the given value. So if you have a following code
* executed in the main thread:
* <pre class="prettyprint">
* liveData.postValue("a");
* liveData.setValue("b");
* </pre>
* The value "b" would be set at first and later the main thread would override it with
* the value "a".
* <p>
* If you called this method multiple times before a main thread executed a posted task, only
* the last value would be dispatched.
*
* @param value The new value
*/
protected void postValue(T value) {
复制代码
3. 总结
本文简单介绍了 JetPack 组件中的一个话题,但不仅仅于此,未完待续,敬请期待。
评论