笔者在开发一款即时通讯和音视频应用时,发现需要花费很大的力量去处理系统组件之间的数据传递,稍微有点不注意,就会出现状态错乱不同步的问题,影响用户体验,也给系统稳定性带来了许多挑战。因此,在我们 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 组件中的一个话题,但不仅仅于此,未完待续,敬请期待。
评论