在使用架构组件的 Android 应用程序中,我有以下 View 模型:
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
成员“结婚”呢?
长话短说
我想更改我的 View 模型以保存 map 而不是列表:
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()
?
更新:
我明天试试下面的(今天晚上太晚了)-
我将更改 Dao 方法以返回列表而不是 LiveData
:
@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);
});
}
};
最佳答案
好吧,更新中的内容可能会起作用,但我不会为每个 setValue()
调用创建一个新的 Executor
— 只创建一个并保持在你的 MutableLiveData
子类中。此外,根据您的 minSdkVersion
,您可以在 HashMap
上使用一些 Java 8 的东西(例如,replaceAll()
)来简化代码有一点。
您可以使用 MediatorLiveData
,但最终我认为它会产生更多代码,而不是更少。因此,虽然从纯度的角度来看 MediatorLiveData
是一个更好的答案,但这可能不是您使用它的好理由。
坦率地说,恕我直言,这类事情并不是 LiveData
的真正目的。如果这是我现在正在处理的代码,我会在其中大部分使用 RxJava,最后转换为 LiveData
。而且,我会在存储库中尽可能多地拥有这些,而不是在 View 模型中。虽然你的未检查到检查的东西将是一个棘手的 RxJava 链来解决,但我仍然更喜欢它而不是 MutableLiveData
子类。
EpicPandaForce 建议的是一种理想的仅 LiveData
方法,尽管我认为他没有完全正确地实现您的算法,而且我怀疑它是否可以轻松地适应您想要的算法。
不过,最后,决定归结为:谁将看到这段代码?
如果此代码仅供您查看,或者将保存在很少有人会看的布满灰尘的 GitHub 存储库中,那么如果您觉得可以维护
MutableLiveData
子类,我们真的不能提示。如果同事要审查此代码,请询问您的同事他们的想法。
如果此代码将由 future 的雇主审查...考虑 RxJava。是的,它有一个学习曲线,但是为了引起雇主的兴趣,他们会更喜欢你知道如何使用 RxJava 而不是你知道如何破解
LiveData
来获得你想要的东西.
关于android - Dao 方法返回 List<String> 而我需要一个 Map<String,Integer>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53804875/