MVVM 架构中的 ViewModel 操作
ViewModel manipulation in MVVM Architecture
我的问题是,在我的视图中显示之前,我需要对房间数据库中的数据进行预处理。
因此这里是我申请的一些上下文:
我正在编写 "record card" android 应用程序。因此,我有一个房间数据库,其中存储了我所有的记录卡。实体中的信息是:
@Entitiy:
- ID
- Question
- Answer
- Topic
- Boxnumber (Box depends on how often i was right with my Answer)
在实体周围,我有正常的房间设置,我在几个教程中找到了:Dao, Database, Repository
。此外,我有一个 ViewModel
连接到 Repository
。还有一个 View
用于显示与 ViewModel
.
相关的当前问题
我的想法:
我的想法是 ViewModel
可以容纳 LiveData
所有需要的卡片(例如特定主题)。
我需要一些关于该数据的算法,它将 select 我的下一张卡片 View
。这取决于:有多少卡片有不同的框号,哪些卡片是最后 10 个问题,等等。
我的问题:
在我的 ViewModel
中,我从 repository
收到 LiveData
。每个教程只显示带有视图的房间数据库数据。但是我需要在 ViewModel
中做一些预处理。使用 .getValue()
访问 LiveData
无效,仅返回 null
对象。观察 ViewModel
中的数据也不起作用,因为为此你需要一个 Activity
。
我不知道应该将处理数据库中数据的算法放在哪里。我不想把它放在 View
中,因为我想将当前算法参数保存在 ViewModel
.
中
一些代码可以更好地理解我的程序:
@道
@Query("SELECT * FROM Karteikarte WHERE BoxnummerMixed = :Boxnummer")
LiveData<List<Karteikarte>> getKarteikartenInBoxMixed(int Boxnummer);
@Query("SELECT * FROM Karteikarte WHERE BoxnummerTopic = :Boxnummer AND Thema = :thema")
LiveData<List<Karteikarte>> getKarteikartenInBoxTopic(int Boxnummer, int thema);
存储库
public LiveData<List<Karteikarte>> getKarteikarteInBoxMixed(int boxnummer){
return karteikarteDao.getKarteikartenInBoxMixed(boxnummer);
}
public LiveData<List<Karteikarte>> getKarteikarteInBoxTopic(Thema thema, int boxnummer){
return karteikarteDao.getKarteikartenInBoxTopic(thema.ordinal(), boxnummer);
}
视图模型
public LearningViewModel(Application application){
super(application);
repository = new KarteikarteRepository(application);
}
//This method will be called from the View at onCreate
public void initLearning(){
allCards = repository.getKarteikarteInBoxMixed(1);
}
//This method will be called from the View
public Karteikarte nextCard() {
// here will be a more complex algorithm
Random random = new Random();
List<Karteikarte> list = allCards.getValue();
return list.get(random.nextInt(list.size()));
}
对于实时数据,您需要使用 LifeCycleOwner(您需要在那个 activity 或存储库或 vm 中实现)。查看 google 中的示例代码以获取实时数据
您可以使用Transformations修改viewModel/Repository中的数据,然后再转到Fragment或Activity
Transforamtions.map 创建一个新的 LiveData,它将观察您传递的 liveData,每当有新数据时,数据将通过您提供的函数传递,然后再将其发送到 Fragment 或 activity
private val liveDataFromRoomDatabase: LiveData<RecordCard> = getFromRoomDatabase()
val recordCardLiveData:LiveData<RecordCard>
= Transformations.map(liveDataFromRoomDatabase){ recordCard ->
// do all the changes you need here and return record card in this function
recordCard
}
对于更复杂的用例,您可以使用 MediatorLiveData
这里我使用了Transformations.switchMap() and Transformations.map()
要详细了解 Transformations 和 MediatorLiveData,您可以观看来自 Android Dev Summit '18 - Fun with LiveData
的视频
private MutableLiveData<Integer> boxNumberLiveData = new MutableLiveData<>();
private final LiveData<List<Karteikarte>> allCardsLiveData;
//Observe this from Fragment or Activity
public final LiveData<Karteikarte> karteikarteLiveData;
LearningViewModel(){
// when ever you change box number below function is called and list of Karteikarte will be updated
allCardsLiveData = Transformations.switchMap(boxNumberLiveData, new Function<Integer, LiveData<List<Karteikarte>>>() {
@Override
public LiveData<List<Karteikarte>> apply(Integer number) {
if(number == null)return null;
return repository.getKarteikarteInBoxMixed(1);
}
});
// when ever list of Karteikarte is changed, below function will be called and a random Karteikarte will be selected
karteikarteLiveData = Transformations.map(allCardsLiveData, new Function<List<Karteikarte>, Karteikarte>() {
@Override
public Karteikarte apply(List<Karteikarte> list) {
return getRandomKarteikarte(list);
}
});
}
public void initLearning(){
//Enter box number here
// you can modify box number anytime you want, everything will change respectively
boxNumberLiveData.setValue(1);
}
private Karteikarte getRandomKarteikarte(@Nullable List<Karteikarte> list){
if(list == null)return null;
Random random = new Random();
return list.get(random.nextInt(list.size()));
}
如果你想获得下一个随机Karteikarte。实现这个的最好方法是在数据库中有一个额外的字段。
@Entitiy:
- ID
- Question
- Answer
- Topic
- Boxnumber (Box depends on how often i was right with my Answer)
- isShown(boolean)
查询数据时需要添加额外的条件 isShown is false
所以当你想加载下一个 Karteikarte 时,你只需要将当前 Karteikarte 的 isShown 字段更新为 true
如果你想重复使用已经显示的 Karteikarte,你可以在你想要启动该过程时将 isShown 值重置为 false
我的问题是,在我的视图中显示之前,我需要对房间数据库中的数据进行预处理。
因此这里是我申请的一些上下文:
我正在编写 "record card" android 应用程序。因此,我有一个房间数据库,其中存储了我所有的记录卡。实体中的信息是:
@Entitiy:
- ID
- Question
- Answer
- Topic
- Boxnumber (Box depends on how often i was right with my Answer)
在实体周围,我有正常的房间设置,我在几个教程中找到了:Dao, Database, Repository
。此外,我有一个 ViewModel
连接到 Repository
。还有一个 View
用于显示与 ViewModel
.
我的想法:
我的想法是 ViewModel
可以容纳 LiveData
所有需要的卡片(例如特定主题)。
我需要一些关于该数据的算法,它将 select 我的下一张卡片 View
。这取决于:有多少卡片有不同的框号,哪些卡片是最后 10 个问题,等等。
我的问题:
在我的 ViewModel
中,我从 repository
收到 LiveData
。每个教程只显示带有视图的房间数据库数据。但是我需要在 ViewModel
中做一些预处理。使用 .getValue()
访问 LiveData
无效,仅返回 null
对象。观察 ViewModel
中的数据也不起作用,因为为此你需要一个 Activity
。
我不知道应该将处理数据库中数据的算法放在哪里。我不想把它放在 View
中,因为我想将当前算法参数保存在 ViewModel
.
一些代码可以更好地理解我的程序:
@道
@Query("SELECT * FROM Karteikarte WHERE BoxnummerMixed = :Boxnummer")
LiveData<List<Karteikarte>> getKarteikartenInBoxMixed(int Boxnummer);
@Query("SELECT * FROM Karteikarte WHERE BoxnummerTopic = :Boxnummer AND Thema = :thema")
LiveData<List<Karteikarte>> getKarteikartenInBoxTopic(int Boxnummer, int thema);
存储库
public LiveData<List<Karteikarte>> getKarteikarteInBoxMixed(int boxnummer){
return karteikarteDao.getKarteikartenInBoxMixed(boxnummer);
}
public LiveData<List<Karteikarte>> getKarteikarteInBoxTopic(Thema thema, int boxnummer){
return karteikarteDao.getKarteikartenInBoxTopic(thema.ordinal(), boxnummer);
}
视图模型
public LearningViewModel(Application application){
super(application);
repository = new KarteikarteRepository(application);
}
//This method will be called from the View at onCreate
public void initLearning(){
allCards = repository.getKarteikarteInBoxMixed(1);
}
//This method will be called from the View
public Karteikarte nextCard() {
// here will be a more complex algorithm
Random random = new Random();
List<Karteikarte> list = allCards.getValue();
return list.get(random.nextInt(list.size()));
}
对于实时数据,您需要使用 LifeCycleOwner(您需要在那个 activity 或存储库或 vm 中实现)。查看 google 中的示例代码以获取实时数据
您可以使用Transformations修改viewModel/Repository中的数据,然后再转到Fragment或Activity
Transforamtions.map 创建一个新的 LiveData,它将观察您传递的 liveData,每当有新数据时,数据将通过您提供的函数传递,然后再将其发送到 Fragment 或 activity
private val liveDataFromRoomDatabase: LiveData<RecordCard> = getFromRoomDatabase()
val recordCardLiveData:LiveData<RecordCard>
= Transformations.map(liveDataFromRoomDatabase){ recordCard ->
// do all the changes you need here and return record card in this function
recordCard
}
对于更复杂的用例,您可以使用 MediatorLiveData
这里我使用了Transformations.switchMap() and Transformations.map()
要详细了解 Transformations 和 MediatorLiveData,您可以观看来自 Android Dev Summit '18 - Fun with LiveData
的视频private MutableLiveData<Integer> boxNumberLiveData = new MutableLiveData<>();
private final LiveData<List<Karteikarte>> allCardsLiveData;
//Observe this from Fragment or Activity
public final LiveData<Karteikarte> karteikarteLiveData;
LearningViewModel(){
// when ever you change box number below function is called and list of Karteikarte will be updated
allCardsLiveData = Transformations.switchMap(boxNumberLiveData, new Function<Integer, LiveData<List<Karteikarte>>>() {
@Override
public LiveData<List<Karteikarte>> apply(Integer number) {
if(number == null)return null;
return repository.getKarteikarteInBoxMixed(1);
}
});
// when ever list of Karteikarte is changed, below function will be called and a random Karteikarte will be selected
karteikarteLiveData = Transformations.map(allCardsLiveData, new Function<List<Karteikarte>, Karteikarte>() {
@Override
public Karteikarte apply(List<Karteikarte> list) {
return getRandomKarteikarte(list);
}
});
}
public void initLearning(){
//Enter box number here
// you can modify box number anytime you want, everything will change respectively
boxNumberLiveData.setValue(1);
}
private Karteikarte getRandomKarteikarte(@Nullable List<Karteikarte> list){
if(list == null)return null;
Random random = new Random();
return list.get(random.nextInt(list.size()));
}
如果你想获得下一个随机Karteikarte。实现这个的最好方法是在数据库中有一个额外的字段。
@Entitiy:
- ID
- Question
- Answer
- Topic
- Boxnumber (Box depends on how often i was right with my Answer)
- isShown(boolean)
查询数据时需要添加额外的条件 isShown is false
所以当你想加载下一个 Karteikarte 时,你只需要将当前 Karteikarte 的 isShown 字段更新为 true
如果你想重复使用已经显示的 Karteikarte,你可以在你想要启动该过程时将 isShown 值重置为 false