Компоненты архитектуры Android и LiveData, слишком много объектов MutableLiveData?

До того, как были выпущены компоненты архитектуры Android, я начал работать над проектом, в котором у меня были собственные модели ViewModels, которые имели тот же жизненный цикл, что и фрагмент, а состояние ViewModels сохранялось в StateObject внутри загрузчика, чтобы состояние могло пережить изменение ориентации. ViewModel взаимодействует с фрагментом через интерфейс. Это сработало нормально, потому что ViewModel и Fragment имели одинаковый жизненный цикл. Моя ViewModel содержала все виды состояний. У него было логическое значение isLoading, логическое значение isEmptyStateVisible и т. Д. И каждый раз, когда состояние изменялось, я вызывал что-то вроде view.notifyIsLoadingChanged (true / false), и в этом случае фрагмент показывал или скрывал счетчик.

Теперь я собираюсь изменить свою реализацию, чтобы использовать новые модели просмотра вместе с LiveData. Самый быстрый способ реализовать LiveData - это изменить мою реализацию интерфейса пользовательского интерфейса, который использует ViewModel. Так что я мог бы сохранить свою текущую реализацию и просто добавить эту реализацию интерфейса пользовательского интерфейса:

public class LiveDataProductReviewSheetUI extends LiveDataUI implements ProductReviewSheetUI {
    public final MutableLiveData<ReviewViewModelState> ratingDescChanged = new MutableLiveData<>();
    public final MutableLiveData<ReviewViewModelState> ratingChanged = new MutableLiveData<>();
    public final MutableLiveData<ReviewViewModelState> reviewChanged = new MutableLiveData<>();
    public final MutableLiveData<ReviewViewModelState> reviewValid = new MutableLiveData<>();
    public final MutableLiveData<ReviewViewModelState> expandReview = new MutableLiveData<>();
    public final MutableLiveData<ReviewViewModelState> reviewQuestion = new MutableLiveData<>();
    public final MutableLiveData<ReviewViewModelState> reviewCreated = new MutableLiveData<>();
    public final MutableLiveData<ReviewViewModelState> showMsg = new MutableLiveData<>();
    public final MutableLiveData<ReviewViewModelState> dismiss = new MutableLiveData<>();

    public void observe(LifecycleOwner owner, final ProductReviewSheetUI observer) {
        ratingDescChanged.observe(owner, state -> observer.onRatingDescriptionChanged(state));
        ratingChanged.observe(owner, state -> observer.onRatingChanged(state));
        reviewChanged.observe(owner, state -> observer.onReviewChanged(state));
        reviewValid.observe(owner, state -> observer.onHasValidReviewDataChanged(state));
        expandReview.observe(owner, state -> observer.onExpandReviewFieldHasChanged(state));
        reviewQuestion.observe(owner, state -> observer.onProductReviewQuestionChanged(state));
        reviewCreated.observe(owner, state -> observer.onReviewCreated(state));
        showMsg.observe(owner, state -> observer.onShowMessage(state));
        dismiss.observe(owner, state -> observer.onCloseView());
    }

    @Override
    public void onRatingDescriptionChanged(ReviewViewModelState state) {
        ratingDescChanged.setValue(state);
    }

    @Override
    public void onRatingChanged(ReviewViewModelState state) {
        ratingChanged.setValue(state);
    }

    @Override
    public void onReviewChanged(ReviewViewModelState state) {
        reviewChanged.setValue(state);
    }

    @Override
    public void onHasValidReviewDataChanged(ReviewViewModelState state) {
        reviewValid.setValue(state);
    }

    @Override
    public void onExpandReviewFieldHasChanged(ReviewViewModelState state) {
        expandReview.setValue(state);
    }

    @Override
    public void onProductReviewQuestionChanged(ReviewViewModelState state) {
        reviewQuestion.setValue(state);
    }

    @Override
    public void onReviewCreated(ReviewViewModelState state) {
        reviewCreated.setValue(state);
    }

    @Override
    public void onShowMessage(ReviewViewModelState state) {
        showMsg.setValue(state);
    }

    @Override
    public void onCloseView() {
        dismiss.setValue(dismiss.getValue());
    }
}

Класс LiveDataUI, который расширяет этот класс, имеет еще больше таких методов, как:

public final MutableLiveData<Boolean> showLoading = new MutableLiveData<>();
public final MutableLiveData<Boolean> showEmptyState = new MutableLiveData<>();

С этой реализацией у меня будет много объектов MutableLiveData, и это кажется неправильным. Я слишком много вкладываю в свою ViewModel? Моя идея заключалась в том, чтобы вся логика была внутри ViewModel, чтобы я мог писать тесты, в которых я мог бы проверить, что isLoading истинно при загрузке данных, и если нет данных, возвращаемых из Api, isEmptyState истинно и т. Д.

Я также заметил, что если я вызываю setValue (state); несколько раз за очень короткое время для одного и того же объекта MutableLiveData метод onChanged вызывается только один раз. Это верно?


person Kasper Finne Nielsen    schedule 17.08.2017    source источник
comment
Я думаю, вы пытаетесь вписать шаблон MVP в MVVM, если вы хотите полностью отделить логику от представления, которое вы должны изучить в MVP или некоторых других шаблонах, MVVM касается привязки моделей к пользовательскому интерфейсу, поэтому всякий раз, когда модель изменяется, это отражается на UI. Вы пытаетесь сделать здесь что-то совершенно другое.   -  person Andrej Jurkin    schedule 17.08.2017
comment
Похоже, что при изменении одного из ваших значений LiveData наблюдатель запускает метод, который снова изменяет LiveData. Мне это кажется циклическим, но, возможно, я не понимаю --- Можете ли вы описать, что делают ваши ViewModel и код активности?   -  person Lyla    schedule 14.10.2017
comment
модель просмотра имеет поле интерфейса ProductReviewSheetUI, а конкретная реализация этого интерфейса - LiveDataProductReviewSheetUI. Таким образом, ViewModel считает, что напрямую обращается к пользовательскому интерфейсу, но на самом деле это LiveData. Фрагмент также реализует ProductReviewSheetUI, поэтому фрагмент является наблюдателем.   -  person Kasper Finne Nielsen    schedule 16.10.2017
comment
У меня та же проблема, что и у вас, слишком много объектов LiveData, что вы в итоге сделали?   -  person DIRTY DAVE    schedule 23.03.2021
comment
Можно ли конвертировать в Котлин? С Kotlin вы можете использовать sealed классы, которые позволят вам объединить все эти объекты LiveData в один.   -  person Ivan    schedule 07.07.2021