В приложении 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
- проверить, какое из слов, переданных в виде списка строк, сделатьсуществует в таблице комнат:
@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);
}
Целые числа были бы оценками слов в моей игре .И как только checkWords()
вернет результаты, я хотел бы установить баллы на null
для слов, не найденных в таблице Room, и оставить остальные баллы такими, какие они есть.
Программный код будетбыть простым (перебрать mChecked.getValue()
и установить null
для слов, не найденных в списке, возвращенном методом DAO) - но как "жениться" на нем с моими 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
:
@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);
});
}
};