【用法总结】LiveData组件要点

发布时间:2024年01月15日

1、如何实现和生命周期的关联?

调用observe()方法时,第一个参数传入LifecycleOwner对象,而LifecycleOwner能通过getLifecycle()方法获取到lifecycle对象,然后执行lifecycle.addObserver()添加LiveData中数据(mData)变化的观察者对象。

  • observe的实现逻辑:
    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            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);
    }

LifecycleOwner-ViewModel-LiveData的层级结构
如上图所示,是使用LiveData组件实现数据更新-订阅的开发模式的层级结构。

  • mData:setValue()之后更新的数据
  • mVersion:在每一次调用setValue()时会进行更新
  • mPending:调用postValue()时先将新的值暂存到该变量中,然后将Runnable任务post()到Handler中后,再将mPendingData
    中的值赋值给mData变量,然后就是走setValue()的流程了。

2、onChange()执行时机

  • (1)onStart()之后调用setValue()立即回调onChanged(newData)

  • (2)调用observe()时,如果Observer是新建的实例,那么其绑定的mLastVersion初始值是-1,当调用lifecycleOwner.addObserver()时会调用activeStateChanged(), 然后触发dispatchingValue(), 因为不满足observe.mLastVersion>=mVersion(默认值是0,每次setValue/postValue加1),然后回调onChanged(newData)
    如果是在onStop()中注册observer,那么会在回到onStart()后会回调一次onChanged()
    ?? LiveData中判断LifecycleOwner是判断生命周期状态是否是isAtLeast(START),所以onPause时调用observe()方法也是会回调onChanged()方法的。

  • (3)LifecycleOwner生命周期变化时,还存在同因生命周期<Lifecycle.State.ON_START并没有回调onChanged(newData),则会回调一次onChanged(),把最新的mData值回调给onChanged()方法

3、说LiveData会数据倒灌是这么回事?

3.1 本质

????LiveData其实本质上实现的是将事件发送时机限定在LifecycleOwner的生命周期内的粘性事件。LiveData在生命周期可见时,将不可见时更新的mData版本回传到onChanged()中。当setValue()是在observe()之前调用的,那调用observe()时会把前面setValue的最新的值传给观察者的onChanged()。
????不使用LiveData进行数据更新时,一般是在UI控件变量准备好了,然后获取数据,再把数据传递给UI控件变量的某个属性,实现UI的更新,这种命令式UI的开发模式本身没有什么问题,符合日常的开发逻辑。
????但是因为Android的UI架构都是基于Activity/Fragment生命周期管理的,就必然存在数据异步获取到时界面已经处于不活跃状态的情况。甚至很可能因为内存不足已经销毁了,然后在用户操作下回到活跃状态了,那么异步拿到的数据可能是没有塞给UI控件的,一般都是在onResume时又异步获取一次数据,然后更新到UI控件上。

3.2 使用LiveData实现事件注册-分发逻辑的问题

????基于3.1对于LiveData数据更新本质的分析,如果我们使用LiveData的setValue/postValue,然后通过observe()分发进行监听,使用String/Int/CustomEvent(自定义的事件类,类似于EventBus)等数据做为事件分发。虽然这种方式能够避免内存泄漏,但是事件是粘性的,先发送事件,然后注册也会接收到该事件,这样的逻辑实际上并不是我们日常业务的事件逻辑。

????google官方sample只处理一次的LiveData事件实现方案:
官方todoapp的Event实现
????ps: 不得不说,老外的文章写得还是蛮清楚的,循序渐进,解释各种方案的问题,层层递进,对读者更好的理解有莫大帮助。

3.3 短时间内连续执行多次postValue,只有最后一次更新的值会收到数据变化的onChanged回调

????这个问题是因为postValue的实现逻辑导致的,如下是postValue的代码:

protected void postValue(T value) {
    boolean postTask;
    synchronized (mDataLock) {
        postTask = mPendingData == NOT_SET;
        mPendingData = value;
    }
    if (!postTask) {
        return;
    }
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}

private final Runnable mPostValueRunnable = new Runnable() {
    @SuppressWarnings("unchecked")
    @Override
    public void run() {
        Object newValue;
        synchronized (mDataLock) {
            newValue = mPendingData;
            mPendingData = NOT_SET;
        }
        setValue((T) newValue);
    }
};

????第一次postValue,postTask是true,mPendingData赋值为value,然后调用mPostValueRunnable.run方法,newValue赋值为mPendingData后,立即又将mPendingData赋值为NOT_SET了。

  • 官方对postValue的备注如下:
    在这里插入图片描述

参考文章

【1】LiveData with SnackBar, Navigation and other events (the SingleLiveEvent case)

文章来源:https://blog.csdn.net/yyg_2015/article/details/135431021
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。