Room和ViewModel,多个查询?

时间:2018-10-21 11:15:22

标签: android android-room android-livedata android-viewmodel

因此,我有一个具有Room数据库的android应用程序,该后端由充当提供我的视图模型的资源库的类管理,然后我的活动(片段)观察该视图模型,(每个人都和我在一起?)在我的一个片段中,我想获得数据库中所有卡(实体)的列表,其单击值高于X,但我也想获得所有标记为收藏的卡,无论其单击值如何。 / p>

我当前的解决方案正在通过存储库从视图模型中运行2个独立的查询,并且我的活动同时观察了这两个查询并将返回的列表合并,这无法正常工作,因为我的列表被加倍了,而我没有观察者在不同的时间回来是因为它们是异步的,所以在清除列表上没有一个好地方(我将发布所有代码)。

我认为我想要以某种方式组合查询,以便仅管理一个列表,但是我的SQL知识不是很好,并且我不确定是否可行,或者我可以以某种方式合并这些列表我的存储库类,但是因为我正在使用实时数据,所以我不确定如何安全地获取数据以合并列表,但是也许有一个我不知道的更好的解决方案,但是我会发布正在执行的操作远低于

DAO查询 这是我运行的两个查询,一个查询使所有卡片点击了x次,另一个查询了所有被标记为收藏的卡片,两者都使用了目前不相关的搜索字符串

@Query("SELECT * FROM card WHERE cardFavourite AND cardWord LIKE :searchWord ORDER BY cardWord ASC")
LiveData<List<Card>> searchFavourites(String searchWord);

@Query("SELECT * FROM card WHERE cardClicked >= :clicks AND cardKeyStage <= :keystage  AND cardWord LIKE :searchWord ORDER BY cardFavourite ASC, cardClicked DESC, cardWord ASC")
LiveData<List<Card>> searchCardListRecents(String searchWord,int clicks, int keystage);

存储库我的存储库是一个充满了对数据库的调用的类,这些调用将实时数据返回到其视图模型,为此需要的是:

public LiveData<List<Card>> searchFavouriteCards(String searchString){
    return cardDao.searchFavourites(searchString);
}

public LiveData<List<Card>> searchRecentCards(String searchString, int clicks){
    return cardDao.searchCardListRecents(searchString,clicks,keystage);
}

视图模型我的视图模型使用切换图(用于搜索)调用存储库方法

public CardFavouritesViewModel(Application application, int clicks){
    cardRepository = new CardRepository(application);
    search = new MutableLiveData<>();
    cardRepository.getCardListByWordTypeAndWordDescription(args[0], args[1]);
    favourites = Transformations.switchMap(search, mySearch -> cardRepository.searchFavouriteCards(mySearch));
    recents = Transformations.switchMap(search, mySearch -> cardRepository.searchRecentCards(mySearch,clicks));
}

public LiveData<List<Card>> getLiveCardFavouriteList(){
    return favourites;
}

public LiveData<List<Card>> getLiveCardRecentsList(){
    return recents;
}

活动,然后我的活动观察到变化,如当前所提到的,这在某种意义上说确实有效,因为它确实获取了相关数据,但是就其复制数据而言却不起作用,我没有有一个显而易见的解决方案,可以在欢迎任何想法时清除列表

ArrayList<Card> cardArrayList = new ArrayList<>();
cardFavouritesViewModel = ViewModelProviders.of(this,
                new 
CardFavouritesViewModelFactory(getActivity().getApplication(),5))
.get(CardFavouritesViewModel.class);
       cardFavouritesViewModel.setSearchString(mSearchString);
       cardFavouritesViewModel.getLiveCardFavouriteList().observe(this, 
       new Observer<List<Card>>() {
            @Override
            public void onChanged(@Nullable List<Card> cards) {
                cardArrayList.addAll(cards);
                cardAdapter.refreshList(cardArrayList);
                checkResults(cardArrayList.size());
            }
        });
        cardFavouritesViewModel.getLiveCardRecentsList().observe(this, 
        new Observer<List<Card>>() {
            @Override
            public void onChanged(@Nullable List<Card> cards) {
                cardArrayList.addAll(cards);
                cardAdapter.refreshList(cardArrayList);
                checkResults(cardArrayList.size());
            }
        });

3 个答案:

答案 0 :(得分:1)

您可以尝试以下操作:

 @Query("SELECT * FROM card WHERE cardFavourite OR (cardClicked >= :clicks AND cardKeyStage <= :keystage)  AND cardWord LIKE :searchWord ORDER BY cardFavourite ASC, cardClicked DESC, cardWord ASC")
    LiveData<List<Card>> searchCardListRecentsAndFavourites(String searchWord,int clicks, int keystage);

答案 1 :(得分:1)

也许此功能会有所帮助:

// Kotlin!!
fun <S, T, R> multiSourceLiveData(source1: LiveData<S>, source2: LiveData<T>, block: (S?, T?) -> R): LiveData<R> = MediatorLiveData<R>().apply {
    var data1: S? = null
    var data2: T? = null

    addSource(source1) {
        data1 = it
        value = block(data1, data2)
    }
    addSource(source2) {
        data2 = it
        value = block(data1, data2)
    }
}

像这样使用它:

    // Kotlin!!
    val allCardsLiveData = multiSourceLiveData(
        source1 = cardFavouritesViewModel.getLiveCardFavouriteList(),
        source2 = cardFavouritesViewModel.getLiveCardFavouriteList()
    ) { data1, data2 ->
        (data1 ?: emptyList()).plus(data2 ?: emptyList())
    }
    allCardsLiveData.observer(this) { allCards ->
        cardAdapter.refreshList(allCards);
        checkResults(cardArrayList.size());
    }

    // Java!!
    LiveData<List<Card>> allCardsLiveData = ExtensionsKt.multiSourceLiveData(
            cardFavouritesViewModel.getLiveCardFavouriteList(),
            cardFavouritesViewModel.getLiveCardRecentsList(),
            new Function2<List<Card>, List<Card>, List<Card>>() {
                @Override
                public List<Card> invoke(List<Card> data1, List<Card> data2) {
                    List<Card> result = new ArrayList<>();
                    if (data1 != null) result.addAll(data1)
                    if (data2 != null) result.addAll(data2)
                    return result;
                }
            });

     allCardsLiveData.observe(...
    

您可以对该函数进行多次重载以支持不同数量的源。

答案 2 :(得分:0)

如果第二个查询已经可以正常使用,则另外一个AND和cardFavourite列将对您有效。

    @Query("SELECT * FROM card WHERE cardFavourite AND cardWord LIKE :searchWord ORDER BY cardWord ASC")
        LiveData<List<Card>> searchFavourites(String searchWord);


   @Query("SELECT * FROM card WHERE cardFavourite AND cardClicked >= :clicks AND cardKeyStage <= :keystage  AND cardWord LIKE :searchWord ORDER BY cardFavourite ASC, cardClicked DESC, cardWord ASC")
        LiveData<List<Card>> searchCardListRecents(String searchWord,int clicks, int keystage);