【发布时间】:2018-12-16 17:46:33
【问题描述】:
在使用架构组件的 Android 应用中,我有以下视图模型:
public class MainViewModel extends AndroidViewModel {
private final MutableLiveData<List<String>> mUnchecked = new MutableLiveData<>();
private LiveData<List<String>> mChecked;
public void setUnchecked(List<String> list) {
mUnchecked.setValue(list);
}
public LiveData<List<String>> getChecked() { // OBSERVED BY A FRAGMENT
return mChecked;
}
public MainViewModel(Application app) {
super(app);
mChecked = Transformations.switchMap(mUnchecked,
list-> myDao().checkWords(list));
}
上述switchMap 的目的是检查作为字符串列表传递的哪些单词确实存在于Room 表中:
@Dao
public interface MyDao {
@Query("SELECT word FROM dictionary WHERE word IN (:words)")
LiveData<List<String>> checkWords(List<String> words);
上面的代码很适合我!
但是我坚持想要一些稍微不同的东西 -
我宁愿传递字符串(单词)-> 整数(分数)的映射,而不是字符串列表:
public void setUnchecked(Map<String,Integer> map) {
mUnchecked.setValue(map);
}
整数将是my game 中的单词分数。一旦checkWords() 返回了结果,我想将Room 表中未找到的单词的分数设置为null,并保留其他分数。
编程代码很简单(遍历mChecked.getValue() 并将DAO 方法返回的列表中未找到的单词设置为null)- 但是如何将它与我的LiveData 成员“结合”?
TL;DR
我想更改我的视图模型以保存地图而不是列表:
public class MainViewModel extends AndroidViewModel {
private final MutableLiveData<Map<String,Integer>> mUnchecked = new MutableLiveData<>();
private final MutableLiveData<Map<String,Integer>> mChecked = new MutableLiveData<>();
public void setUnchecked(Map<String,Integer> map) {
mUnchecked.setValue(map);
}
public LiveData<Map<String,Integer>> getChecked() { // OBSERVED BY A FRAGMENT
return mChecked;
}
public MainViewModel(Application app) {
super(app);
// HOW TO OBSERVE mUnchecked
// AND RUN myDao().checkWords(new ArrayList<>(mUnchecked.getValue().keys()))
// WRAPPED IN Executors.newSingleThreadScheduledExecutor().execute( ... )
// AND THEN CALL mChecked.postValue() ?
}
请问如何实现?我应该扩展MutableLiveData 还是使用MediatorLiveData 或者使用Transformations.switchMap()?
更新:
我明天试试下面的(今天晚上太晚了)-
我将改成返回列表而不是LiveData的Dao方法:
@Query("SELECT word FROM dictionary WHERE word IN (:words)")
List<String> checkWords(List<String> words);
然后我会尝试扩展MutableLiveData:
private final MutableLiveData<Map<String,Integer>> mChecked = new MutableLiveData<>();
private final MutableLiveData<Map<String,Integer>> mUnchecked = new MutableLiveData<Map<String,Integer>>() {
@Override
public void setValue(Map<String,Integer> uncheckedMap) {
super.setValue(uncheckedMap);
Executors.newSingleThreadScheduledExecutor().execute(() -> {
List<String> uncheckedList = new ArrayList<>(uncheckedMap.keySet());
List<String> checkedList = WordsDatabase.getInstance(mApp).wordsDao().checkWords(uncheckedList);
Map<String,Integer> checkedMap = new HashMap<>();
for (String word: uncheckedList) {
Integer score = (checkedList.contains(word) ? uncheckedMap.get(word) : null);
checkedMap.put(word, score);
}
mChecked.postValue(checkedMap);
});
}
};
【问题讨论】:
-
我不完全理解你的算法。是“未选中”
Map<String, Integer>单词的键吗?如果是这样,那么虽然我知道你想用null替换checkWords()未返回的单词的Integer,但是对于@返回的单词are,你想要发生什么987654344@?您要单独留下Integer吗?还是您正在计算一个恰好不是null的新值? -
感谢您查看我的问题!是的,完全正确:地图的键是单词,值是由Scrabble-like 游戏板上的单词形成的分数。一旦在 Room 表中检查了单词的存在,我想将无效单词的分数替换为
null并保留其他分数。我正在考虑扩展MutableLiveData,不确定这是否是正确的路径(请参阅更新后的问题)。
标签: android android-room android-architecture-components android-livedata