Android LiveData - 第二次更新时不会触发switchMap

时间:2017-11-21 19:30:14

标签: android android-architecture-components android-livedata android-architecture-lifecycle

我有一个LiveData对象依赖于另一个LiveData。据我了解,Transformations.switchMap应该允许链接它们。但是switchMap处理程序只触发一次,并且它不会对进一步的更新做出反应。相反,我在第一个对象上使用observe,当它准备就绪时,检索第二个对象,它可以正常工作但在这种情况下我必须在Activity而不是{{1 }}。是否可以链接ViewModel对象,例如LiveData,但是接收所有更新,而不仅仅是第一个?

以下是尝试使用Transformations.switchMap

switchMap

这是一种在活动中使用LiveData<Resource<User>> userLiveData = usersRepository.get(); return Transformations.switchMap(userLiveData, resource -> { if (resource.status == Status.SUCCESS && resource.data != null) { return apiService.cartItems("Bearer " + resource.data.token); } else { return AbsentLiveData.create(); } }); 的方法(有效,但需要将逻辑保留在活动中):

observe

2 个答案:

答案 0 :(得分:3)

我正在尝试做与您相似的事情。我有一个LiveData something,当发生更改时,我想根据属性从数据库查询somethingElse。因为该属性可以为null,所以如果我用它查询数据库,则会得到一个异常。因此,如果该属性为null,则返回一个空的MutableLiveData。

我注意到,当我返回此空MutableLiveData时,订阅somethingElse的观察者没有得到任何更新。我看到您在answer上最终使用了MediatorLiveData。然后,我在调试器中逐步执行了代码,并注意到switchMap也使用MediatorLiveData。

经过一些试验,我意识到在创建空的MutableLiveData时,其初始值为null,并且不会触发任何更新。如果我明确设置了该值,那么它将通知观察者。

somethingElse = Transformations.switchMap(something, somethingObject -> {
                if (something.someProperty() != null) {
                    return repository.getSomethingElseByProperty(something.someProperty());
                }else{
                    MutableLiveData<SomethingElse> empty = new MutableLiveData<>();
                    empty.setValue(null);//need to set a value, to force update of observers
                    return empty;
                }

这里的代码对我有用。在问题中,您使用了一个AbsentLiveData,我不知道它是如何实现的,因此我不确定它在这种情况下是否可以正常工作。

答案 1 :(得分:1)

作为解决方法,我使用了MediatorLiveData。我将第一个调用的结果添加为源,当它准备就绪时,将其替换为最终调用:

MediatorLiveData<MyResponse> result = new MediatorLiveData<>();
LiveData<Resource<User>> source = this.get();
result.addSource(source, resource -> {
    if (resource.status == Status.SUCCESS && resource.data != null) {
        result.removeSource(source);
        result.addSource(apiService.cartItems("Bearer " + resource.data.token), result::postValue);
    }
});
return result;