7

我有一个LiveData依赖于另一个的对象LiveData。据我了解,Transformations.switchMap应该允许链接它们。但是switchMap处理程序仅触发一次,并且不会对进一步的更新做出反应。相反,如果我observe在第一个对象上使用,当它准备好时,检索第二个,它工作正常,但在这种情况下,我必须在Activity而不是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活动中的方法(有效,但需要保持活动中的逻辑):

viewModel.user().observe(this, x -> {
    if (x != null && x.data != null) {
        viewModel.items(x.data.token).observe(this, result -> {
            // use result
        });
    }
});
4

2 回答 2

3

我试图做一些与你类似的事情。我有一个 LiveData something,当它发生变化时,我想somethingElse根据属性从数据库中查询。因为属性可以为空,如果我用它查询数据库,我会得到一个异常。因此,如果该属性为空,我将返回一个空的 MutableLiveData。

我注意到,当我返回这个空的 MutableLiveData 时,订阅的观察者somethingElse没有得到任何更新。我在您的回答中看到您最终使用了 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,我不知道它是如何实现的,所以我不确定它在这种情况下是否能正常工作。

于 2020-01-23T07:58:15.450 回答
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;
于 2017-12-28T11:34:38.407 回答