Room 和 ViewModel,多个查询?
Room and ViewModel, multiple queries?
所以我有一个 android 应用程序,它有一个 Room 数据库,这个后端由一个 class 管理,它充当一个存储库,为我的视图模型提供数据,然后是我的 activity(片段)观察视图模型,(每个人都和我在一起吗?)在我的一个片段中我想获得我数据库中所有卡片(实体)的列表,点击值高于 X 但我也想获得所有无论点击值如何都被标记为收藏的卡片。
我当前的解决方案是 运行通过我的存储库从我的视图模型中创建 2 个单独的查询,我 activity 观察这两个查询并将列表 return 合并到它,这不能正常工作,因为我的列表被加倍了,而且我没有一个很好的地方来清除列表,因为观察者在不同的时间回来,因为它们是异步的(我将 post 所有代码).
我想我想要的是以某种方式组合查询,以便我只管理一个列表,但我的 SQL 知识不多,我不确定这是否可行,或者我可以以某种方式将这些列表合并到我的存储库 class 但因为我正在使用实时数据,所以我不确定如何安全地获取数据以合并列表,但也许有更好的解决方案我不知道但是我会 post 我目前所做的事情低于
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 我的存储库是一个 class 充满了对数据库的调用,return 实时数据到他们的视图模型,需要的是:
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());
}
});
如果第二个查询已经运行良好,那么再添加一个 AND with 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);
您可以尝试这样的操作:
@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);
也许这个功能会有帮助:
// 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(...
您可以对函数进行多次重载以支持不同数量的源。
所以我有一个 android 应用程序,它有一个 Room 数据库,这个后端由一个 class 管理,它充当一个存储库,为我的视图模型提供数据,然后是我的 activity(片段)观察视图模型,(每个人都和我在一起吗?)在我的一个片段中我想获得我数据库中所有卡片(实体)的列表,点击值高于 X 但我也想获得所有无论点击值如何都被标记为收藏的卡片。
我当前的解决方案是 运行通过我的存储库从我的视图模型中创建 2 个单独的查询,我 activity 观察这两个查询并将列表 return 合并到它,这不能正常工作,因为我的列表被加倍了,而且我没有一个很好的地方来清除列表,因为观察者在不同的时间回来,因为它们是异步的(我将 post 所有代码).
我想我想要的是以某种方式组合查询,以便我只管理一个列表,但我的 SQL 知识不多,我不确定这是否可行,或者我可以以某种方式将这些列表合并到我的存储库 class 但因为我正在使用实时数据,所以我不确定如何安全地获取数据以合并列表,但也许有更好的解决方案我不知道但是我会 post 我目前所做的事情低于
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 我的存储库是一个 class 充满了对数据库的调用,return 实时数据到他们的视图模型,需要的是:
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());
}
});
如果第二个查询已经运行良好,那么再添加一个 AND with 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);
您可以尝试这样的操作:
@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);
也许这个功能会有帮助:
// 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(...
您可以对函数进行多次重载以支持不同数量的源。