【问题标题】:Room and ViewModel, multiple queries?Room 和 ViewModel,多个查询?
【发布时间】:2018-10-21 11:15:21
【问题描述】:

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

我当前的解决方案是通过我的存储库从我的视图模型中运行 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);

Repository 我的存储库是一个对数据库进行调用的类,这些调用将实时数据返回到他们的视图模型,为此需要的是:

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;
}

Activity 然后我的 Activity 观察到变化,正如目前所提到的,这在某种意义上是有效的,它确实获得了相关数据,但它在复制数据方面不起作用,而我没有有一个明显的解决方案可以在完成任何想法时清除列表

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());
            }
        });

【问题讨论】:

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


    【解决方案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);
    

    【讨论】:

    • 但我两者都想要,我想要所有标记为收藏的卡片,以及点击值高于 X 的卡片,不过我还没有尝试过你的答案,所以当我有机会时我会更新这个跨度>
    • 你得到了两个:我在查询中使用 OR 运算符,即如果记录标记为收藏,你得到它,如果点击 > x 你也在结果中得到它
    【解决方案2】:

    也许这个功能会有所帮助:

    // 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(...
        
    

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

    【讨论】:

      【解决方案3】:

      如果第二个查询已经正常工作,那么另一个与 cardFavourite 列的 AND 将为您工作。

          @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);
      

      【讨论】:

      • 这不会返回标记为收藏的卡片,点击值为 0,我最初在我的问题中没有明确说明,所以我对其进行了编辑以使其更清晰,我想要所有卡片标记为收藏,以及所有价值高于点击次数的卡片,即使它们不是收藏
      猜你喜欢
      • 1970-01-01
      • 2022-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-13
      • 1970-01-01
      相关资源
      最近更新 更多