[JetPack] LiveData源码解析

本文介绍了在开发即时通讯和音视频应用时,如何利用LiveData解决数据同步和状态错乱问题。LiveData作为Android架构组件,确保界面与数据状态一致,避免内存泄漏和Activity崩溃。通过创建ViewModel和Observer,实现数据更新与UI同步,并通过MutableLiveData的setValue和postValue方法更新数据。在使用中需注意多线程环境下postValue的顺序问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 背景 官网LiveData

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

未完待续,敬请期待
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值