【发布时间】:2019-07-16 10:27:04
【问题描述】:
问题:
switchMap 转换在其结果必须有一个活动的观察者之前不会触发。即使没有观察者,我也试图触发 switchMap 转换。谁能建议我如何实现此功能?下面有一些描述当前场景的代码。
如何重现:
在 ProfileViewModel 中,UI 可以观察到两个不同的 LiveData
- profileLiveData:观察个人资料数据
- profileApiStateLiveData :观察从后端获取配置文件数据的 Http Call 的状态
ProfileViewModel.java
public class ProfileViewModel extends AndroidViewModel {
private MutableLiveData<Boolean> getProfileCommand = new MutableLiveData<>();
public ProfileViewModel(@NonNull Application application) {
super(application);
profileLiveData = Transformations.switchMap(getProfileCommand, forceUpdate -> UserRepository.getInstance().getProfile(forceUpdate));
profileApiStateLiveData = UserRepository.getInstance().getProfileApiRequestStatus();
}
public void loadProfile(boolean forceUpdate) {
getProfileCommand.postValue(forceUpdate);
}
// Profile Data : Observable Field
private LiveData<Profile> profileLiveData;
public LiveData<Profile> getProfileLiveData() {
if(profileLiveData == null) profileLiveData = new MutableLiveData<>();
return profileLiveData;
}
// Profile Http Call's State : Observable Field
private LiveData<ApiRequest> profileApiStateLiveData;
public LiveData<ApiRequest> getProfileApiStateLiveData() {
if(profileApiStateLiveData == null) profileApiStateLiveData = new MutableLiveData<>();
return profileApiStateLiveData;
}
}
现在 UI 可以观察到配置文件数据和 Http 调用状态的变化。 所以如果一个 UI 想要下载并在 UI 上显示 Profile,UI 负责观察 profileLiveData 和 profileApiStateLiveData 然后调用 ViewModel 的方法 loadProfile(true);
// Observes Profile Data
mProfileViewModel.getProfileLiveData().observe(this, profileData -> {
// Use profile data here
});
// Observes State of Profile Http Call
mProfileViewModel.getProfileApiStateLiveData().observe(this, profileHttpCallState -> {
// show/hide progress based on http call state
});
// start downloading profile data
mProfileViewModel.loadProfile(true);
我们可以看到,loadProfile方法会触发switchMap Transformation,并启动Http Call。请注意,switchMap 触发的发生是因为 UI 正在观察结果 LiveData,即 profileLiveData。
此方案运行良好。但是如果某个Activity只想发起Http调用,只想观察profileApiStateLiveData而不是profileLiveData,那么switchMap Trigger永远不会发生,这是因为没有结果 LiveData profileLiveData 的积极观察者。
/**** Do not observe Profile Data, because here we only need to observe Http Call State ***/
/**** Only Observe State of Profile Http Call ***/
mProfileViewModel.getProfileApiStateLiveData().observe(this, profileHttpCallState -> {
// show/hide progress based on http call state
});
/**** start downloading profile data ***/
mProfileViewModel.loadProfile(true);
/**** The above line does not trigger the switchMap Transformation. ***/
我有一个丑陋的解决方案,我必须在 UI 中为 profileLiveData 添加一个不必要的空白观察者。但这很容易出错,因为其他开发人员可能会忘记为 profileLiveData 添加这个不必要的空白观察者,并且即使他们正在调用该方法,他们也不知道为什么没有获取配置文件数据强>loadProfile(true).
非常感谢 Rx 专家的帮助 :-)
【问题讨论】:
-
不知道为什么要以这种方式设计这两个 LiveData。在获取数据时,为什么不更新
profileLiveData和profileApiStateLiveData。或者,如果您有一个直接使用它发出 LiveData 映射profileLiveData的数据库层? -
这两个 LiveData 都直接来自房间数据库。 http层(WorkManager)正在分别更新这些表记录。
-
那么我会让
profileLiveData直接从数据库发出数据,而不是在profileApiStateLiveData更改时发出数据。当 DB 中的数据发生变化时,profileLiveData应该发出新数据。profileApiStateLiveData应该只在 API 状态发生变化时发出变化。
标签: android rx-android android-architecture-components android-livedata