Где сохранять сырые данные MVP?

135
13 января 2021, 19:00

Для реализации MVP использую Moxy. Сегодня в первый раз использую данную либу, может уже из коробки есть решения возникших вопросов, но я не знаю о них. В целом вопрос больше в плане как это сделать не нарушая канонов MVP...

Да, я знаю что в Moxy сохраняется ViewState при обращении из презентера getViewState().showData(data);

Есть фрагмент, в котором запись редактируется(если она ранее была создана) или создается новая запись. Если фрагмент открываем в режиме редактирования то в Arguments передаю ID записи который нужно редактировать.

На самом деле у меня возникло 3 вопроса по этому кэйсу:

  1. Когда презентер получает данные из репозитория(например, из сети), он должен его кэшировать в своем private поле? например, для последующей модификации при изменении из вьюшки (например, меняем текст в EditText)..

  2. В случае если мы заходим в режиме редактирования, презентер подгружает информацию о редактируемой записе(например, MyData) и отправляет вьюшке для отображения. Теперь, пользователь редактирует запись(меняет текст в EditText, добавляет фото) - что должно происходить в этот момент? При любых изменениях мы должны эти изменения отправлять в презентер? Вот так:

    presenter.addImage(imagePath);

    presenter.editTitle(newTitleText);

    и что дальше презентер с этим должен делать? Модифицировать сохраненное в private поле из п.1 данные с помощью полученных в методах addImage и editTitle данными?

  3. Какая будет логика в пунктах выше, если зашли в режиме создания новой записи?

  4. Пункт №2, №3 интересны из-за пересоздания View при смене конфигурации.. Где же сохранять "сырые" данные?

Интересует как вы решаете такие кейсы! Как это сделать по умному не нарушая принципы паттерна MVP?

оффтоп: И еще, где-то читал, что, код типа этого: presenter.addImage(imagePath); неправильный, view не должно говорить презентуру что делать, а тут я говорю добавь фото. Или я просто неправильно понял ту мысль которую излагали?!

Если все же я правильно понял, то я в ступоре..) Например, во вьюшке кликнул кнопку "добавить фото", презентер узнал об этом и отправил вьюшке команду "открой окно выбора", в этом окне я выбрал фото(из галереи), далее в onActivityResult получаю путь выбранной картинки, и по сути я должен с этой картинкой что то делать, или выполнить presenter.addImage(imagePath) или сообщить презентуру что, что то произошло и презентер должен это как-то обработать(а в этот момент пока я сообщаю презентеру и презентер как то начинает это обрабатывать где будет храниться картинка которая пришла в onActivityResult ? где то во вью? тогда получается вьюшка уже занимается не только вопросами UI). А как вообще на практике это решается? какой подход считается общепринятым? - вопрос для всех кто прочитает))

Answer 1
  1. Когда презентер получает данные из репозитория(например, из сети), он должен его кэшировать в своем private поле?

Лучше кэшировать данные в репозитории, потому что репозиторий ответственен за управлением источниками данных(сети, базы, кеша). Здесь много разных подходов, я написал тот, который предлагает гугл.

  1. и 3. Как работает презентер и вью при редактировании записи, при добавлении новой записи?

Контракт (если хотите, можете оформить в виде интерфейса презентера) может быть такой:

public interface INotePresenter {
    void saveClicked();
    void imageChosen(File file);
    void editTitleClicked(String title);
}

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

Презентер можете создать через метод мокси

    @ProvidePresenter
    NotePresenter provideNotePresenter() {
        Bundle bundle = this.getArguments();
        int id = Objects.requireNonNull(bundle).getInt(NOTE_ID, 0);
        if( id == 0){
           return new NotePresenter();
        }else{
           return new NotePresenter(id)
        }
    }

В пустом конструкторе вы ничего не делаете. В конструкторе с айдишником делаете запрос в ваш репозиторий и устанавливаете getViewState().showData(data);

Остальные методы презентера проксируете(оборачиваете) в репозиторий. Можно только названия поменять на addImage(file), addTitle(title)

Уже в репозитории при вызове метода getData(id) вы кэшируете ваш объект mData, как глобальную переменную private MyData mData = new MyData(); .

При вызове imageChosen(file) добавляете путь файла в кеше(объекте mData).

При вызове editTitleClicked(String title) обновляете тайтл в mData .

Метод saveClicked() можно сделать примерно таким:

 private void saveClicked(){
        if(mData.getId() == 0){
            mDb.insert(mData);  
        }else{
            mDb.update(mData);
        }
    }

Если у вашего айтема есть айдишник, то значит он был взят из бд и айтем надо обновить, если нет то значит это читсый кеш нового айтема и его надо вставить.

Answer 2
  1. Да. Не запрашивать же одни и те же данные на каждый чих
  2. На мой взгляд тут зависит от того чего вы хотите. Вы можете на каждое изменение во вьюхе менять модель, а можете поменять модель 1 раз после нажатия на кнопку Save. Что бы вы не выбрали, вы должны сохранить именные данные в своем репозитории и вернуть новый объект сохранив его в приватное поле.
  3. Мне кажется, что точно такая же, как в пункте 3.

Создали пустой объект, отобразили на вьюхе, его отредактировали и сохранили, вы сохранили в репозитории, который вернул новый объект в итоге, например с присвоенным ID.

  1. Например, в .NET есть DataTable, где каждая строка хранит несколько состояний: Original, Proposed ,Current. Так вот, когда происходит какая-то модификация значение переносится в поле Proposed и Current. Когда значения комитятся, то все 3 состояния равны. Т.е как вариант, вы можете в свою модель добавить хранение промежуточного состояния.
READ ALSO
Как работает HashSet?

Как работает HashSet?

Всё отработало и показало 1 - Sts, то есть исключило дубликатОбъясните почему везде пишется что нужно переопределить hashCode()иequals() чтобы это заработало...

147
как настроить мониторинг Java приложения в Zabbix?

как настроить мониторинг Java приложения в Zabbix?

Есть примитивное приложение Java:

137
Как передать List из Java в JNI (C++) по сслыке?

Как передать List из Java в JNI (C++) по сслыке?

у меня есть функция написаная на C++(JNI) которая получает как параметр jobject (это по сути мой List) и заполняет его данными

117
Помогите с побитовыми операциями

Помогите с побитовыми операциями

Вот пример из книги которую читаю и совершенно не понимаю вот этого (fs&1 > 0) и аналогичных далее выражений

140