我现在正在使用最新的Android体系结构组件,尤其是ViewModel和LiveData。

我的情况是SingleLiveEvent建议的here是相关的,即我返回了错误,并且只想显示一次警报。在向Activity传递值之前,我需要将错误映射到该 View 的一个更合适的对象。我为此使用了转换。

所以最后,我有一个ViewModel看起来像:

public LiveData<ViewState> getStateForView() {
    final LiveData<NetworkState> liveState = myRepository.getState();
    return Transformations.map(liveState, myMapper::map);
}

我在存储库中的哪个位置使用SingleLiveEvent:
public LiveData<NetworkState> getState() {
    myNetworkState = new SingleLiveEvent<>();
    return myNetworkState;
}

这工作得很好,但是我注意到方向改变多次时,事件不会一直传播。调试时,我注意到观察者注册和删除之间没有对称性:
  • 在注册时,我的SingleLiveEvent的观察者是我的SingleLiveEvent中的匿名Observer类

  • android - LiveData-将SingleLiveEvent与转换一起使用-LMLPHP
  • 在删除时,要从我的SingleLiveEvent中删除的观察者是MediatorLiveData(实际上正在观察我的SingleLiveEvent中较早的匿名类)

    android - LiveData-将SingleLiveEvent与转换一起使用-LMLPHP

    发生的事情是,我的初始观察者从未从SingleLiveEvent的观察者中删除(因此,如果方向发生多次更改,则我的SingleLiveEvent会有多个观察者)。

    我无法弄清楚为什么在移除时这不是同一位观察者。在不执行“转换”步骤的情况下进行复制时,不会出现此类问题。

    有人对此行为有暗示吗? SingleLiveEvent(不是框架的一部分)和Transformations是否不应该一起工作?

    最佳答案

    我发现这是由于Transformations使用MediatorLiveData,它使用SingleLiveEvent作为引用源。此源用于注册和注销本身作为观察员。

    但是,SingleLiveEvent在注册时引入了中间观察者。 SingleLiveEvent引用此中间观察者,并且不知道MediatorLiveData

    在删除时,MediatorLiveData尝试从SingleLiveEvent中注销自己作为观察者的身份。由于SingleLiveEvent不知道,因此保留了中间观察者。

    最后,该过程不是对称的,并且随着时间的流逝(随着用户转动电话),SingleLiveEvent具有越来越多的观察者。

    我不知道我是否错过了某件事,或者是否不将MediatorLiveDataSingleLiveEvent一起使用,但是我找到了针对自己特定问题的解决方案。

    我在SingleLiveEvent中添加了对中间观察者的引用,并且重写了removeObserver()方法以除去中间观察者,而不是(仅)MediatorLiveData。我对这种解决方案不是很自信,因为我不熟悉LiveData的内部。特别是,仅当SingleLiveEvent仅与MediatorLiveData一起用作观察者时(例如,如果Activity观察到SingleLiveEvent时才如此),并且只有一个观察者时(对于SingleLiveEvent才有意义),此解决方案才有效。可能还有其他限制。

    这是我添加的用于删除正确观察者的代码(singleLiveEventIntermediateObserver是在Observer方法中实例化的匿名observe()):

    @Override
    public void removeObserver(@NonNull Observer<T> observer) {
        super.removeObserver(observer);
        if (this.singleLiveEventIntermediateObserver != null) {
            super.removeObserver(this.singleLiveEventIntermediateObserver);
        }
    }
    

  • 10-06 15:00