Манипулирование ViewModel в архитектуре MVVM - PullRequest
0 голосов
/ 12 ноября 2018

Моя проблема в том, что мне нужно предварительно обработать данные из базы данных комнат, прежде чем показывать их в моем представлении.

Поэтому вот некоторый контекст моего приложения:

Я программирую приложение для 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 всех необходимых карт (например, с определенной темой). Мне нужен алгоритм для этих данных, который выберет мне мою следующую карту, которая мне нужна для View. Это зависит от того: сколько карт имеют разные номера ящиков, какие карты были последними 10 вопросами и т. Д.

Моя проблема:

В моем ViewModel я получаю LiveData от repository. Каждый учебник показывает только отображение данных базы данных комнаты с представлением. Но мне нужно сделать некоторую предварительную обработку внутри ViewModel. Доступ к LiveData с помощью .getValue() не работает и возвращает только null объекты. Наблюдение за данными в ViewModel также не работает, потому что для этого вам нужен Activity.

Я не знаю, куда мне поместить алгоритм работы с данными из базы данных. Я не хочу помещать его в View, потому что я хочу хранить текущие параметры алгоритма внутри ViewModel.

Код для лучшего понимания моей Программы:

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

Репозиторий

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

Ответы [ 3 ]

0 голосов
/ 12 ноября 2018

Вы можете использовать Преобразования для изменения данных в viewModel / Repository перед переходом к Фрагменту или Деятельности

Transforamtions.map создает новые LiveData, которые будут наблюдать живые данные, которые вы передаете, и когда бы то ни былоесть новые данные, данные будут переданы через функцию, которую вы предоставляете перед отправкой во фрагмент или действие

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

0 голосов
/ 12 ноября 2018

Здесь я использовал Transformations.switchMap () и Transformations.map ()

Для подробного понимания преобразований и 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()));
}

Если вы хотите получить следующую случайную Karteikarte.Лучший способ реализовать это - иметь дополнительное поле в базе данных.

@Entitiy:
- ID
- Question
- Answer
- Topic
- Boxnumber (Box depends on how often i was right with my Answer)
- isShown(boolean)

при запросе данных вам нужно добавить дополнительное условие, которое isShown is false, поэтому, когда вы хотите загрузить следующую Karteikarte, вам просто нужночтобы обновить текущее поле isShown Karteikarte на true

, если вы хотите повторно использовать уже показанную Karteikarte, вы можете просто сбросить значения isShown на false, если вы хотите запустить процесс

0 голосов
/ 12 ноября 2018

для живых данных вам нужно использовать LifeCycleOwner (вам нужно реализовать в этом то действие, или хранилище, или vm). Проверьте примеры кодов в google для живых данных

...