[英]ViewModel manipulation in MVVM Architecture
My Problem is, that i need to preprocess data from the Room Database before showing it in my View. 我的问题是,我需要先对会议室数据库中的数据进行预处理,然后才能在视图中显示它。
Therefore here some Context of my Application: 因此,这里是我的应用程序的一些上下文:
Im programming a "record card" android application. 我正在编写“记录卡” android应用程序。 Therefore i have a Room Database where all my record-cards are stored. 因此,我有一个房间数据库,其中存储了我所有的记录卡。 The Information in the Entitiy is: 实体中的信息是:
@Entitiy:
- ID
- Question
- Answer
- Topic
- Boxnumber (Box depends on how often i was right with my Answer)
Around the Entity i have the normal Room Setup, i found in several tutorials, with: Dao, Database, Repository
. 我在实体周围有正常的房间设置,我在一些教程中找到了它们,包括: Dao, Database, Repository
。 Furthermore i have a ViewModel
connected to the Repository
. 此外,我有一个ViewModel
连接到Repository
。 And a View
for showing the current Question connected to the ViewModel
. 还有一个用于显示当前Question的View
连接到ViewModel
。
My Idea: 我的点子:
My Idea was that the ViewModel
can hold LiveData
of all needed Cards (with a specific Topic for example). 我的想法是, ViewModel
可以保存所有需要的Cards的LiveData
(例如,带有特定的Topic)。 I need some algorithm on that data which will select me my next Card i need for the View
. 我需要一些关于该数据的算法,它将选择我需要View
下一张卡片。 This depends on: How much cards have different boxnumbers, which cards was the last 10 Questions, etc. 这取决于:多少张卡具有不同的箱号,哪些卡是最近的10个问题,等等。
My Problem: 我的问题:
In my ViewModel
i recieve LiveData
from the repository
. 在我的ViewModel
我从repository
接收LiveData
。 Every Tutorial shows only displaying the Room-Database Data with an View. 每个教程仅显示带有视图的Room-Database数据。 But i need to do some preprocessing inside the ViewModel
. 但是我需要在ViewModel
内部做一些预处理。 Accessing the LiveData
with .getValue()
is not working and only returning null
objects. 使用.getValue()
访问LiveData
不起作用,仅返回null
对象。 Observing the Data in the ViewModel
is also not working, because you need an Activity
for this. 在ViewModel
观察数据也不起作用,因为为此您需要一个Activity
。
I don't know where i should place the algorithm working with the data from the database. 我不知道该将算法与数据库中的数据一起放置在哪里。 I don't want to put it in the View
because i want to hold the current algorithm parameters inside the ViewModel
. 我不想将其放在View
因为我想在ViewModel
保存当前算法参数。
Some Code to understand my Program better: 一些代码可以更好地理解我的程序:
@Dao @道
@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);
Repository 资料库
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);
}
ViewModel 视图模型
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()));
}
You can use Transformations to modify data in viewModel/Repository before going to Fragment or Activity 您可以在进入Fragment或Activity之前使用Transformations修改viewModel / Repository中的数据
Transforamtions.map creates a New LiveData which will observe the liveData that you pass and when ever there is new data, The data will be passed though the function you provide before sending it to the Fragment or 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
}
For more complex use cases you can use MediatorLiveData 对于更复杂的用例,可以使用MediatorLiveData
Here i have used Transformations.switchMap() and Transformations.map() 在这里,我使用了Transformations.switchMap()和Transformations.map()
For detail understanding of Transformations and MediatorLiveData, you can watch this Video from Android Dev Summit '18 - Fun with LiveData 要了解转换和MediatorLiveData的详细信息,您可以观看Android Dev Summit '18的视频-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()));
}
If you want to get the next random Karteikarte. 如果您想获得下一个随机的Karteikarte。 The best way to implement this is to have a extra field in database. 最好的实现方法是在数据库中有一个额外的字段。
@Entitiy:
- ID
- Question
- Answer
- Topic
- Boxnumber (Box depends on how often i was right with my Answer)
- isShown(boolean)
while querying the data you need to add extra condition that isShown is false
so when you want to load next Karteikarte, you just need to update the current Karteikarte's isShown field to true 在查询数据时,需要添加isShown is false
额外条件,因此当您要加载下一个Karteikarte时,只需将当前Karteikarte的isShown字段更新为true
if you want to re-use already shown Karteikarte, you can just reset isShown values to false when you want start the process 如果要重新使用已显示的Karteikarte,则可以在开始过程时将isShown值重置为false
对于实时数据,您需要使用LifeCycleOwner(您需要在该活动或存储库或vm中实施)。检查google中的示例代码以获取实时数据
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.