Вопросы об обязанностях каждого компонента в компонентах архитектуры Android

Я давно использую MVP и начинаю переходить в гибридное состояние между MVP и MVVM

Подробно мои приложения будут выглядеть так:

  • Каждое действие имеет от 0 до x фрагментов, которые представляют его представления.
  • Каждый фрагмент будет запрашивать ViewModel действия, чтобы они могли извлекать данные с помощью LiveData.
  • У Activity будет отдельная ViewModel, которая будет выступать в качестве докладчика. При создании в эту ViewModel будет добавлен ViewModel Activity с LiveData, чтобы он мог обновлять пользовательский интерфейс по мере необходимости.
  • Докладчик получит сообщения, отправленные в модель ViewModel данных, и отправит ей результаты.

Мои вопросы:

  1. Может ли сохранение ссылки на ViewModel данных в ViewModel презентатора вызвать утечку памяти или побочные эффекты, такие как утечки памяти?
  2. Где должна быть бизнес-логика? в ведущей или в модельной части?

Например, предположим, что у меня есть список элементов, и пользователь долго нажимает один, чтобы отредактировать их, какая часть этой архитектуры должна отвечать за проверку того, есть ли у пользователя разрешение на это, и либо позволить ему редактировать элемент, либо показать ошибку сообщение?

  1. Есть ли способ для фрагментов получить только часть ViewModel Activity?

Например, предположим, что под действием есть 3 фрагмента и одна ViewModel для их обслуживания.

Могу я использовать что-то вроде:

class MainViewModel : ViewModel() , IFragmentA, IFragmentB, IFragmentC

а затем, когда я пытаюсь получить ViewModel по фрагментам, я могу написать что-то вроде:

lateinit var viewModel: IFragmentA

override fun onAttach(context: Context?) {
    super.onAttach(context)
    vm = ViewModelProviders.of(context as AppCompatActivity).get(IFragmentA::class.java)
}

примечание: я знаю, что приведенный выше код не работает, я спрашиваю, есть ли способ, чтобы что-то подобное могло сработать

  1. Правильный ли способ отправки сообщений активности SingleEvents?

Например, если пользователь пытается удалить запись, а я хочу, чтобы он ввел пароль, поток будет следующим:

  • Фрагмент отправляет сообщение для удаления своей ViewModel.
  • ViewModel передает его докладчику.
  • Ведущий решает, что ему необходимо проверить пароль, прежде чем продолжить
  • Ведущий устанавливает значение SingleEvent в ViewModel.
  • ViewModel уведомляет подписчиков события (в данном случае MainActivity), что они должны показать диалоговое окно с запросом пароля.

Спасибо за любую помощь, которую вы можете предоставить


person Cruces    schedule 19.04.2019    source источник
comment
Я бы предпочел не делать это гибридным, вместо этого вам следует полностью перейти на MVVM или оставаться на треке MVP.   -  person Jeel Vankhede    schedule 23.04.2019
comment
@Cruces вы используете кинжал в своем проекте?   -  person HourGlass    schedule 24.04.2019
comment
@JeelVankhede, да, я тоже склоняюсь к этому пути, но я все еще не уверен, попробую в паре приложений и посмотрю, как пойдет   -  person Cruces    schedule 24.04.2019
comment
@HourGlass нет, я не использую инъекции через вызовы конструкторов, когда я стану более опытным с MVVM, я тоже начну изучать / использовать кинжал   -  person Cruces    schedule 24.04.2019


Ответы (1)


Недавно я перенес одно из своих приложений с MVP на архитектуру MVVM. Неважно, делаете ли вы это частично или полностью, вы движетесь к чему-то великому и чистому, и вам это понравится.

Прежде чем проверять ответ, ознакомьтесь с этой схемой архитектуры MVVM и некоторыми из того, что можно и чего нельзя делать.

Архитектура MVVM

Давайте посмотрим на роли каждого класса здесь.

Действие / фрагмент:

-Слушайте MutableLiveData Obeservers и установите Data для представлений, никакой другой логики здесь нет.

ViewModel

  • пользовательский ввод Проверки (пустое имя пользователя, пароль или пустые проверки)
  • установите свой mutableLive
  • попросить репозиторий запустить сетевую задачу или локальное хранилище данных (sqlite) с обратными вызовами.

Репозиторий

  • кешировать необходимые данные.
  • не должен содержать ссылку на ViewModel, это создаст циклическую зависимость.
  • Решает, что делать - делать ли сетевой вызов или загружать данные из локального хранилища. здесь происходит манипулирование полученными данными (бизнес-логика).
  • используйте обратный вызов, полученный от ViewModel, для обновления данных до viewModel, строго без прямой связи.

RemoteDataSource

  • выполняет сетевой вызов и возвращает полученные данные в репозиторий.

LocalDataSource

  • обрабатывает все, что связано с SQLite, и передает запрошенные данные через обратные вызовы.

существует пример проекта приложения todo от google, в котором используется MVVM. пожалуйста, обратитесь к нему, это будет очень полезно.

  1. Нет докладчика - проверяйте вводимые пользователем данные на модели просмотра и общайтесь с помощью репозитория и обратно с помощью MutableLiveData.
  2. Сделайте свою бизнес-логику в репозитории, считайте ее больше моделью в шаблоне mvp.
  3. У вас может быть единая viewModel для вашей деятельности и ее фрагментов. Все ваши фрагменты общаются через одну модель просмотра. Таким образом, каждый фрагмент будет реагировать только на LiveDataObserver, который он слушает.

Фактически есть пример этого варианта использования в демонстрационном проекте Google для MVVM.

AddEditTaskActivity.java

public static AddEditTaskViewModel obtainViewModel(FragmentActivity activity) {
       // Use a Factory to inject dependencies into the ViewModel        
 ViewModelFactoryfactory= ViewModelFactory.getInstance(activity.getApplication());
 return ViewModelProviders.of(activity, factory).get(AddEditTaskViewModel.class);
   }

AddEditTaskFragment.java

 @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        final View root = inflater.inflate(R.layout.addtask_frag, container, false);
        if (mViewDataBinding == null) {
            mViewDataBinding = AddtaskFragBinding.bind(root);
        }

        mViewModel = AddEditTaskActivity.obtainViewModel(getActivity());

        mViewDataBinding.setViewmodel(mViewModel);
        mViewDataBinding.setLifecycleOwner(getActivity());

        setHasOptionsMenu(true);
        setRetainInstance(false);

        return mViewDataBinding.getRoot();
    }

  1. Password Verification Flow:
    • fragment ask the ViewModel to deleteEntry.
    • Попросите репозиторий решить, нужна ли проверка с данными, которые у нас уже есть, или с данными, связанными с локальным источником данных.
    • ViewModel получает обратный вызов из репозитория о необходимости проверки, ViewModel обновляет соответствующий MutableLiveData showVerification.postValue (true);
    • Поскольку действие прослушивает showVerificationObserver, оно показывает пользовательский интерфейс проверки.

Надеюсь, это поможет.

person HourGlass    schedule 24.04.2019
comment
Кажется, в моих спецификациях я называю докладчиком то, что вы называете репозиторием, потому что, на мой взгляд, ведущий, которого я хотел использовать, делает эти вещи (решает, кому звонить, каков рабочий процесс и тому подобное), спасибо за ссылка на проект, это интересно, я обязательно прочитаю и попробую ваше решение, посмотрю, как оно у меня работает - person Cruces; 24.04.2019