Java Android LiveData调用Room查询依赖其他LiveData
Java Android LiveData calls Room query dependent on other LiveData
更新:::
我更新了问题以包括演示其他还需要的 LiveData:
所以我们有 userLD,我们需要它的值来获取 goalWeeklyLD,我们需要 goalWeeklyLD 值来获取剩余的 4 个 LiveData 值,因为它们来自在查询 goalWeekly.dateproperties 中使用
的 Room 查询
::::::
我遇到了一个问题,我有一个片段必须填充使用依赖于另一个 LiveData 值的查询的 LiveData。
当我的实时数据依赖于其他结果时,我如何才能使它正常工作?
在不使用 Transitions.map() 的情况下,视图模型会抛出错误,因为其他实时数据的值仍然为空。
使用视图模型中的 Transitions.map() 时,活动观察器会抛出错误,因为 LiveData 仍然为空。
我可能会通过使用一个非常大的嵌套查询来绕过这个问题 return 我在一个自定义 DTO 中所需要的一切。但我更想了解这里发生了什么以及如何正确处理这种情况。
希望一些代码能说明这一点
Activity:
public class SomeFragment extends Fragment {
public static SomeFragment newInstance() {
return new SomeFragment();
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
someViewModel = ViewModelProviders.of(this).get(SomeViewModel.class);
//getting user details from previous activity
Intent intent = getActivity().getIntent();
if (intent != null){
if (intent.hasExtra(USER_ID)){
user = new User(intent.getStringExtra(USERNAME));
user.setId(intent.getLongExtra(USER_ID,0));
someViewModel.setUserLD(user);
}
}
someViewModel.getUserLD().observe(this, new Observer<User>() {
@Override
public void onChanged(@Nullable User userVal) {
user = userVal;
}
});
someViewModel.getGoalWeeklyLD().observe(this, new Observer<User>() {
@Override
public void onChanged(@Nullable User userVal) {
user = userVal;
}
});
//the below Observer calls throw an error because LiveData is null. makes sense.
//but how can i say "don't try and observe these until the transition.map has ran (because then it wont be null after if my understanding is right)" or something to that effect
someViewModel.getFirstLD(user.getId()).observe(this, new Observer<XObject>() {
@Override
public void onChanged(@Nullable Grades avgSportGradeVal) {
//Update UI
}
});
someViewModel.getSecondLD(user.getId()).observe(this, new Observer<XObject>() {
@Override
public void onChanged(@Nullable Grades avgBoulderGradeVal) {
// Update UI
}
});
someViewModel.getThriLD(user.getId()).observe(this, new Observer<XObject>() {
@Override
public void onChanged(@Nullable Grades avgBoulderGradeVal) {
// Update UI
}
});
someViewModel.getFourthLD(user.getId()).observe(this, new Observer<XObject>() {
@Override
public void onChanged(@Nullable Grades avgBoulderGradeVal) {
// Update UI
}
});
}}
视图模型:
public class SomeViewModel extends AndroidViewModel {
DaoRepository daoRepository;
MutableLiveData<User> userLD;
LiveData<XObject> firstLD;
LiveData<XObject> secondLD;
LiveData<XObject> thirdLD;
LiveData<XObject> fourthLD;
public MutableLiveData<User> getUserLD() {
return userLD;
}
public void setUserLD(User user){
userLD.setValue(user);
}
public LiveData<XObject> getFirstLD(long userId) {
return goalWeeklyLD;
}
public LiveData<XObject> getSecondLD(long userId) {
return goalWeeklyLD;
}
public LiveData<XObject> getThirdLD(long userId) {
return goalWeeklyLD;
}
public LiveData<XObject> getForthLD(long userId) {
return goalWeeklyLD;
}
public SomeViewModel(@NonNull Application application) {
super(application);
daoRepository = new DaoRepository(application);
userLD = new MutableLiveData<>();
//so the first LiveData waits for the user to be populated before getting its LiveData becasue we need the userId for our Room query to run
firstLD = Transformations.map(userLD, user -> daoRepository.getMostRecentGoalWeekly(user.getId()).getValue());
//the remaining live data uses values from the first...
setupOtherTransformMaps(userLD.getValue())
}
public void setupOtherTransformMaps(long userId) {
//the secondLD, thirdLD and fourthLD all depends on values from the first (in runs a query that uses its dateExpired)
secondLD = Transformations.map(firstLD, first ->
daoRepository.getAvgGradeRouteInPeriod(userId, first.getDateCreated(),first.getDateExpires()).getValue());
thirdLD = Transformations.map(firstLD, first ->
daoRepository.getAvgGradeRouteInPeriod(userId, first.getDateCreated(),first.getDateExpires()).getValue());
fourthLD = Transformations.map(firstLD, first ->
daoRepository.getAvgGradeRouteInPeriod(userId, first.getDateCreated(),first.getDateExpires()).getValue());
}}
谢天谢地 Google 很聪明,他创建了一个组件,让您可以将可变数量的 LiveData 合并到一个 LiveData 中,并且仅在您选择这样做时才发出事件!
这称为 MediatorLiveData。
但在您的情况下,您只需要将 1 个 LiveData (userLD
) 导入另一个 1 个 LiveData,每次 userLd
有新值时都会发出。
因此您可以使用预定义的 MediatorLiveData 来完成此操作,特别是 Transformations.switchMap
。
firstLD = Transformations.switchMap(userLD, user -> daoRepository.getMostRecentGoalWeekly(user.getId()));
编辑: 是的,您似乎需要将这些 LiveData 彼此分开公开,但它们都依赖于第一个查询来执行。
因此,您需要将 Transformations.map { ...getValue()
替换为 Transformations.switchMap
,这样就可以了。
public SomeViewModel(@NonNull Application application) {
super(application);
CustomApplication app = (CustomApplication) application;
daoRepository = app.daoRepository();
userLD = new MutableLiveData<>();
firstLD = Transformations.switchMap(userLD, user -> daoRepository.getMostRecentGoalWeekly(user.getId()));
secondLD = Transformations.switchMap(firstLD, first ->
daoRepository.getAvgGradeRouteInPeriod(userId, first.getDateCreated(),first.getDateExpires()));
thirdLD = Transformations.switchMap(firstLD, first ->
daoRepository.getAvgGradeRouteInPeriod(userId, first.getDateCreated(),first.getDateExpires()));
fourthLD = Transformations.switchMap(firstLD, first ->
daoRepository.getAvgGradeRouteInPeriod(userId, first.getDateCreated(),first.getDateExpires()));
}
更新:::
我更新了问题以包括演示其他还需要的 LiveData: 所以我们有 userLD,我们需要它的值来获取 goalWeeklyLD,我们需要 goalWeeklyLD 值来获取剩余的 4 个 LiveData 值,因为它们来自在查询 goalWeekly.dateproperties 中使用
的 Room 查询::::::
我遇到了一个问题,我有一个片段必须填充使用依赖于另一个 LiveData 值的查询的 LiveData。 当我的实时数据依赖于其他结果时,我如何才能使它正常工作?
在不使用 Transitions.map() 的情况下,视图模型会抛出错误,因为其他实时数据的值仍然为空。 使用视图模型中的 Transitions.map() 时,活动观察器会抛出错误,因为 LiveData 仍然为空。
我可能会通过使用一个非常大的嵌套查询来绕过这个问题 return 我在一个自定义 DTO 中所需要的一切。但我更想了解这里发生了什么以及如何正确处理这种情况。
希望一些代码能说明这一点
Activity:
public class SomeFragment extends Fragment {
public static SomeFragment newInstance() {
return new SomeFragment();
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
someViewModel = ViewModelProviders.of(this).get(SomeViewModel.class);
//getting user details from previous activity
Intent intent = getActivity().getIntent();
if (intent != null){
if (intent.hasExtra(USER_ID)){
user = new User(intent.getStringExtra(USERNAME));
user.setId(intent.getLongExtra(USER_ID,0));
someViewModel.setUserLD(user);
}
}
someViewModel.getUserLD().observe(this, new Observer<User>() {
@Override
public void onChanged(@Nullable User userVal) {
user = userVal;
}
});
someViewModel.getGoalWeeklyLD().observe(this, new Observer<User>() {
@Override
public void onChanged(@Nullable User userVal) {
user = userVal;
}
});
//the below Observer calls throw an error because LiveData is null. makes sense.
//but how can i say "don't try and observe these until the transition.map has ran (because then it wont be null after if my understanding is right)" or something to that effect
someViewModel.getFirstLD(user.getId()).observe(this, new Observer<XObject>() {
@Override
public void onChanged(@Nullable Grades avgSportGradeVal) {
//Update UI
}
});
someViewModel.getSecondLD(user.getId()).observe(this, new Observer<XObject>() {
@Override
public void onChanged(@Nullable Grades avgBoulderGradeVal) {
// Update UI
}
});
someViewModel.getThriLD(user.getId()).observe(this, new Observer<XObject>() {
@Override
public void onChanged(@Nullable Grades avgBoulderGradeVal) {
// Update UI
}
});
someViewModel.getFourthLD(user.getId()).observe(this, new Observer<XObject>() {
@Override
public void onChanged(@Nullable Grades avgBoulderGradeVal) {
// Update UI
}
});
}}
视图模型:
public class SomeViewModel extends AndroidViewModel {
DaoRepository daoRepository;
MutableLiveData<User> userLD;
LiveData<XObject> firstLD;
LiveData<XObject> secondLD;
LiveData<XObject> thirdLD;
LiveData<XObject> fourthLD;
public MutableLiveData<User> getUserLD() {
return userLD;
}
public void setUserLD(User user){
userLD.setValue(user);
}
public LiveData<XObject> getFirstLD(long userId) {
return goalWeeklyLD;
}
public LiveData<XObject> getSecondLD(long userId) {
return goalWeeklyLD;
}
public LiveData<XObject> getThirdLD(long userId) {
return goalWeeklyLD;
}
public LiveData<XObject> getForthLD(long userId) {
return goalWeeklyLD;
}
public SomeViewModel(@NonNull Application application) {
super(application);
daoRepository = new DaoRepository(application);
userLD = new MutableLiveData<>();
//so the first LiveData waits for the user to be populated before getting its LiveData becasue we need the userId for our Room query to run
firstLD = Transformations.map(userLD, user -> daoRepository.getMostRecentGoalWeekly(user.getId()).getValue());
//the remaining live data uses values from the first...
setupOtherTransformMaps(userLD.getValue())
}
public void setupOtherTransformMaps(long userId) {
//the secondLD, thirdLD and fourthLD all depends on values from the first (in runs a query that uses its dateExpired)
secondLD = Transformations.map(firstLD, first ->
daoRepository.getAvgGradeRouteInPeriod(userId, first.getDateCreated(),first.getDateExpires()).getValue());
thirdLD = Transformations.map(firstLD, first ->
daoRepository.getAvgGradeRouteInPeriod(userId, first.getDateCreated(),first.getDateExpires()).getValue());
fourthLD = Transformations.map(firstLD, first ->
daoRepository.getAvgGradeRouteInPeriod(userId, first.getDateCreated(),first.getDateExpires()).getValue());
}}
谢天谢地 Google 很聪明,他创建了一个组件,让您可以将可变数量的 LiveData 合并到一个 LiveData 中,并且仅在您选择这样做时才发出事件!
这称为 MediatorLiveData。
但在您的情况下,您只需要将 1 个 LiveData (userLD
) 导入另一个 1 个 LiveData,每次 userLd
有新值时都会发出。
因此您可以使用预定义的 MediatorLiveData 来完成此操作,特别是 Transformations.switchMap
。
firstLD = Transformations.switchMap(userLD, user -> daoRepository.getMostRecentGoalWeekly(user.getId()));
编辑: 是的,您似乎需要将这些 LiveData 彼此分开公开,但它们都依赖于第一个查询来执行。
因此,您需要将 Transformations.map { ...getValue()
替换为 Transformations.switchMap
,这样就可以了。
public SomeViewModel(@NonNull Application application) {
super(application);
CustomApplication app = (CustomApplication) application;
daoRepository = app.daoRepository();
userLD = new MutableLiveData<>();
firstLD = Transformations.switchMap(userLD, user -> daoRepository.getMostRecentGoalWeekly(user.getId()));
secondLD = Transformations.switchMap(firstLD, first ->
daoRepository.getAvgGradeRouteInPeriod(userId, first.getDateCreated(),first.getDateExpires()));
thirdLD = Transformations.switchMap(firstLD, first ->
daoRepository.getAvgGradeRouteInPeriod(userId, first.getDateCreated(),first.getDateExpires()));
fourthLD = Transformations.switchMap(firstLD, first ->
daoRepository.getAvgGradeRouteInPeriod(userId, first.getDateCreated(),first.getDateExpires()));
}