LiveData原理探索


更新一下,添加了 LiveData 粘性消息的原因分析和解决方案

1.LiveData

LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。生命周期处于 STARTED或 RESUMED 状态,则 LiveData 会认为该观察者处于活跃状态。LiveData 只会将更新通知给活跃的观察者。为观察 LiveData 对象而注册的非活跃观察者不会收到更改通知。

2.原理

借助Lifecycle组件实现,observe方法需要传递一个Observer观察者

2.1 observe方法

Observer进行封装,并将其添加为生命周期Lifecycle的观察者

public void observe(LifecycleOwner owner, Observer<? super T> observer) {
    assertMainThread("observe");
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        // ignore
        return;
    }
    // 对Observer进一步封装,LifecycleBoundObserver间接实现LifecycleObserver接口,实现对
    // 生命周期的响应
    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 LifecycleBoundObserver#onStateChanged

添加的Observe实际实现,重写了LifecycleonStateChanged方法来实现在活跃状态时分发数据

public void onStateChanged(@NonNull LifecycleOwner source,
       @NonNull Lifecycle.Event event) {
   Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
   // 当前状态为DESTROYED时移除观察者
   if (currentState == DESTROYED) {
       removeObserver(mObserver);
       return;
   }
   Lifecycle.State prevState = null;
   while (prevState != currentState) {
       prevState = currentState;
       activeStateChanged(shouldBeActive());
       currentState = mOwner.getLifecycle().getCurrentState();
   }
}

void activeStateChanged(boolean newActive) {
   // 状态没有发生改变
   if (newActive == mActive) {
       return;
   }
   // immediately set active state, so we'd never dispatch anything to inactive
   // owner
   mActive = newActive;
   changeActiveCounter(mActive ? 1 : -1);
   // 变成活跃状态时分发数据
   if (mActive) {
       dispatchingValue(this);
   }
}
复制代码

2.3 数据分发给观察者

数据分发有两个时机:

  • 主动调用LiveData的setValue或者postValue(也是调用setValue)方法时
  • 当持有LiveData的生命组件的生命周期状态发生该变的时候,在Observer的onStateChanged方法中调用
// 第一种情况下参数为null, 第二种情况参数为当前Observer
void dispatchingValue(@Nullable ObserverWrapper initiator) {
    if (mDispatchingValue) {
        mDispatchInvalidated = true;
        return;
    }
    mDispatchingValue = true;
    do {
        mDispatchInvalidated = false;
        if (initiator != null) {
            // 第二种情况,当前Observer的数据分发
            considerNotify(initiator);
            initiator = null;
        } else {
            // 第一种情况,遍历对所有Observer进行数据分发
            for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                    mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                considerNotify(iterator.next().getValue());
                if (mDispatchInvalidated) {
                    break;
                }
            }
        }
    } while (mDispatchInvalidated);
    mDispatchingValue = false;
}


private void considerNotify(ObserverWrapper observer) {
    if (!observer.mActive) {
        return;
    }
    if (!observer.shouldBeActive()) {
        observer.activeStateChanged(false);
        return;
    }
    // 观察者数据版本领先了,不用更新
    // mVersion在setValue修改,表示LiveData的最新版本
    // mLastVersion是Observer当前获取的数据的最新版本
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    observer.mLastVersion = mVersion;
    // 调用我们在observe方法中传递的代码
    observer.mObserver.onChanged((T) mData);
}
复制代码

3.LiveData粘性消息

3.1 粘性消息产生原因

当我们在 Fragment 页面中通过 activityViewModels 获取 ViewModel 进行数据共享的场景下,例如:在一个页面发送一个网络请求,当网络请求失败通过 ViewModel 向 LiveData 中设置一个 errorMsg,当我们关闭该页面后又重新进入该页面时,在没有进行任何操作的情况下,就会先收到请求失败的消息。这就是 LiveData 的粘性消息导致的。

由于我们通过 activityViewModels 获取的 ViewModel 的声明周期比 Fragment 的生命周期更长,在第一次关闭 Fragment 时,ViewModel 没有随着 Fragment 销毁,自然其中的 LiveData 也还存在。当我们在一次进入该 Fragment 的时候通过 vm.observe()为 LiveData 注册观察者,LifecycleBoundObserver是实际的类型。

下面详细分析一下 LiveData Observer 添加的代码。

// 1、为 LiveData 绑定 Observer
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    assertMainThread("observe");
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        // ignore
        return;
    }
    // 1.1、创建 LifecycleBoundObserver
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
    
    // 1.2、保存创建的 observer
    // mObservers 是一个 Map
    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;
    }
    // 1.3、 将 创建的 LifecycleBoundObserver 注册为 Lifcycle 的观察者
    owner.getLifecycle().addObserver(wrapper);
}

// 2、对用户传递的 observer 进行包装,内部持有用户传递的 observer
private abstract class ObserverWrapper {
    final Observer<? super T> mObserver; // 用户传递的 obserber
    boolean mActive;
    int mLastVersion = START_VERSION;    // observer 当前的数据版本,默认值为 -1

    ObserverWrapper(Observer<? super T> observer) {
        mObserver = observer;
    }

    abstract boolean shouldBeActive();

    boolean isAttachedTo(LifecycleOwner owner) {
        return false;
    }

    void detachObserver() {
    }

    void activeStateChanged(boolean newActive) {
        if (newActive == mActive) {
            return;
        }
        // immediately set active state, so we'd never dispatch anything to inactive
        // owner
        mActive = newActive;
        changeActiveCounter(mActive ? 1 : -1);
        // 如果变成活跃状态则分发数据
        if (mActive) {
            dispatchingValue(this);
        }
    }
}

// 3、继承 ObserverWrapper,持有用户传递的 Observer,同时实现 LifecycleEventObserver 来感知生命周期
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
    @NonNull
    final LifecycleOwner mOwner;

    LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
        super(observer);
        mOwner = owner;
    }

    @Override
    boolean shouldBeActive() {
        return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
    }

    // 感知生命周期
    @Override
    public void onStateChanged(@NonNull LifecycleOwner source,
            @NonNull Lifecycle.Event event) {
        Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
        if (currentState == DESTROYED) {
            removeObserver(mObserver);
            return;
        }
        
        // 生命周期变成活跃或者不活跃的情况
        Lifecycle.State prevState = null;
        while (prevState != currentState) {
            prevState = currentState;
            // 父类的方法
            activeStateChanged(shouldBeActive());
            currentState = mOwner.getLifecycle().getCurrentState();
        }
    }

    @Override
    boolean isAttachedTo(LifecycleOwner owner) {
        return mOwner == owner;
    }

    @Override
    void detachObserver() {
        mOwner.getLifecycle().removeObserver(this);
    }
}
复制代码

可以看到在为 LiveData 添加 Observer 时,内部会创建出 LifecycleBoundObserver,该类继承 ObserverWrapper 类,同时实现了LifecycleEventObserver 接口,ObserverWrapper 内部持有我们传递的 Observer,而 LifecycleEventObserver 时 Lifecycle 中的观察者,其 onStateChanged 方法会在生命周期发生变化时回调,因此我们注册的 Observer 就可以感知生命周期,并且只在生命周期处于活跃状态的情况下才触发 LiveData 的数据分法。

上文2.3 节有提到 LiveData 数据分发的时机,一种时我们通过 setValue 改变 LiveData 时触发的对所有 Obserber 进行分发,另一种就是在 Observer 内部触发的,即在 LifecycleBoundObserver 感知到生命周期发生变化时触发了 onStateChanged方法,其中调用 activeStateChanged 方法,在检测到生命周期处于活跃状态时分发数据。

此时我们就能够知道 LiveData 粘性数据产生的原因:Fragment 第二次进入页面时,注册的 Observer 检测到生命周期变成活跃状态,于是就想起分发了之前的数据,因此第二次进入 Fragment 的时候,我们什么也没操作就收到了数据。(这里还涉及到 Lifecycle 的一点内容,即 Lifecycle 会对后注册的观察者分发之前的生命周期事件,因此即使我们注册 LiveData的观察者时生命周期组件处于以活跃状态,但是观察者(LifecycleBoundObserver)仍然可以收到变成活跃状态的回调)。

3.2 粘性消息的处理

上文介绍了 LiveData 粘性消息产生的原因,下面介绍一下解决方案。

// 包装 LiveData 内部的变量,记录是否已经处理过了
open class Event<out T>(private val content: T) {

    var hasBeenHandled = false
        private set

    fun getContentIfNotHandled(): T? {
        return if (hasBeenHandled) {
            null
        } else {
            hasBeenHandled = true
            content
        }
    }
    fun peekContent(): T = content
}



// 对 Observer 也进行一层包装,接收到分发的数据时先判断是否之前处理过
class EventObserver<T>(private val onEventUnhandledContent: (T) -> Unit) : Observer<Event<T>> {
    override fun onChanged(event: Event<T>?) {
        event?.getContentIfNotHandled()?.let {
            onEventUnhandledContent(it)
        }
    }
}
//----------------------------使用时 --------------------------------
val l = EventObserver<Event<String>>()
l.observe(this, Observer {
})
复制代码

参考

猜你喜欢

转载自juejin.im/post/6990920733375332366