Dao方法返回List< String>而我需要Map< String,Integer> [英] Dao method returns List<String> while I need a Map<String,Integer>

查看:173
本文介绍了Dao方法返回List< String>而我需要Map< String,Integer>的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在使用架构组件的Android应用中,我具有以下视图模型:

In an Android app using Architecture Components I have the following view model:

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表中是否存在作为字符串列表传递的单词:

The purpose of the above switchMap is to check, which of the words passed as a list of strings, do exist in a Room table:

@Dao
public interface MyDao {
    @Query("SELECT word FROM dictionary WHERE word IN (:words)")
    LiveData<List<String>> checkWords(List<String> words);

上面的代码对我来说很好!

The above code works well for me!

但是我一直想要一些稍微不同的东西-

However I am stuck with wanting something slightly different -

我希望传递字符串(单词)->整数(分数)的映射,而不是字符串列表:

Instead of the list of strings, I would prefer to pass a map of strings (words) -> integers (scores):

    public void setUnchecked(Map<String,Integer> map) {
        mUnchecked.setValue(map);
    }

整数将是null,并保持其他得分不变.

The integers would be word scores in my game. And once the checkWords() has returned the results, I would like to set the scores to null for the words not found in the Room table and leave the other scores as they are.

编程代码很容易(通过mChecked.getValue()进行迭代,对于DAO方法返回的列表中未找到的单词,将其设置为null)-但是如何将其与我的LiveData成员结合"?

The programming code would be easy (iterate through mChecked.getValue() and set to null for the words not found in the list returned by the DAO method) - but how to "marry" it with my LiveData members?

TL; DR

我想将视图模型更改为保存地图而不是列表:

I would like to change my view model to hold maps instead of the lists:

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()?

How to achieve that please? Should I extend MutableLiveData or maybe use MediatorLiveData or maybe use Transformations.switchMap()?

更新:

明天我将尝试以下内容(今天为时已晚)-

I will try the following tomorrow (today is too late in the evening) -

我将更改的Dao方法以返回列表,而不是LiveData:

The Dao method I will change to return a list instead of 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())来简化代码.

Well, what you have there in the update probably works, though I wouldn't create a new Executor for every setValue() call — create just one and hold onto it in your MutableLiveData subclass. Also, depending on your minSdkVersion, you might use some of the Java 8 stuff on HashMap (e.g., replaceAll()) to simplify the code a bit.

您可以使用MediatorLiveData,尽管最后我认为它将导致更多的代码,而不是更少的代码.因此,尽管从纯度的角度来看MediatorLiveData是一个更好的答案,但这可能不是您使用它的好理由.

You could use MediatorLiveData, though in the end I think it would result in more code, not less. So, while from a purity standpoint MediatorLiveData is a better answer, that may not be a good reason for you to use it.

坦白说,这类事情并不是LiveData真正针对的东西,恕我直言.如果这是我现在正在处理的代码,那么我将大量使用RxJava,最后将其转换为LiveData.而且,我将在仓库中而不是在视图模型中尽可能多地使用它.尽管您的未检查内容将是一个棘手的RxJava链,但我仍然希望它优于MutableLiveData子类.

Frankly, this sort of thing isn't what LiveData is really set up for, IMHO. If this were my code that I were working on right now, I'd be using RxJava for the bulk of it, converting to LiveData in the end. And, I'd have as much of this as possible in a repository, rather than in a viewmodel. While your unchecked-to-checked stuff would be a tricky RxJava chain to work out, I'd still prefer it to the MutableLiveData subclass.

EpicPandaForce提出的建议是仅使用LiveData的理想方法,尽管我认为他不能完全正确地实现您的算法,并且我怀疑它是否可以轻松地适应您所需的算法.

What EpicPandaForce suggests is an ideal sort of LiveData-only approach, though I don't think he is implementing your algorithm quite correctly, and I am skeptical that it can be adapted easily to your desired algorithm.

不过,最终决定还是归结为:谁将看到此代码?

In the end, though, the decision kinda comes down to: who is going to see this code?

  • 如果该代码仅供您使用,或者将存在于尘土飞扬的GitHub存储库中,而很少有人看过,那么,如果您觉得可以维护MutableLiveData子类,我们将无法抱怨.

  • If this code is for your eyes only, or will live in a dusty GitHub repo that few are likely to look at, then if you feel that you can maintain the MutableLiveData subclass, we can't really complain.

如果该代码将由同事审核,请询问您的同事他们的想法.

If this code is going to be reviewed by co-workers, ask your co-workers what they think.

如果该代码将由潜在雇主审查...考虑使用RxJava.是的,它具有学习曲线,但是为了使雇主感兴趣,与您知道如何使用RxJava相比,知道如何使用RxJava会给他们留下更深刻的印象.

If this code is going to be reviewed by prospective employers... consider RxJava. Yes, it has a learning curve, but for the purposes of getting interest from employers, they will be more impressed by you knowing how to use RxJava than by you knowing how to hack LiveData to get what you want.

这篇关于Dao方法返回List&lt; String&gt;而我需要Map&lt; String,Integer&gt;的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆