android - Dao 方法返回 List<String> 而我需要一个 Map<String,Integer>

标签 android android-room android-architecture-components android-livedata

在使用架构组件的 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/

相关文章:

android - 如何在 Room 持久性库中使用外键

android - 缓存在 Android Paging 3 中不起作用

java - Android TCP 服务器客户端通信

java - android.support.v7.widget.AppCompatImageView 无法转换为 android.view.ViewGroup

android - Urban Airship Android GCM 未在 Android Oreo 和 Pie 上接收推送通知

android - 当日期更改且未调用 onCreate 时更改数据库中观察到的行

Android ROOM 持久化复杂对象

android - 在 Android 的 Repository 或 ViewModel 中使用共享的 Preference 值

android - 由于缺少方法导致的预启动报告失败(在 com.google.android.apps.mtaas.crawler-1/base.apk 中)

java - 如何管理同步任务中的线程数