Model-view-intent патерн в android
Тепер у View є модель, яку вона і відображає. Ця концепція не нова. В оригінальному описі MVC патерну від Реенскауга Трюгве йдеться майже про те ж: View спостерігає за зміною Моделі. Але, на жаль, MVC. описуваний в багатьох шаблонах, не те ж саме що сформулював Реенскауг Трюгве в 1979 році.
Backend основним розробником використовують MVC фреймворки, у iOS розробників є ViewController. Але! Де ж MVC в Android. Чи є Activity контролером? Що таке ClickListener. У наш час MVC зовсім не те, що сформулював один раз Реенскауг ... Але давайте продовжимо, поки не потонули в холіваров.
Давайте повернемося назад до того про що говорилося на початку. Наявність правильної моделі вирішує багато проблем в Android з якими ми нерідко стикаємося в процесі розробки програми. Таких як:
- Проблема стану програми (State problem)
- Зміна орієнтації екрану
- Навігація по back stack
- Знищення процесу / програми (Process death)
- Незмінюваність даних (Immutability and unidirectional data flow)
- Налагодження і відтворення стану
- можливість тестування
Давайте поговоримо відштовхуючись від цих проблем як вирішуються вони в традиційному розумінні патерном MVP і MVVM. І подивимося як правильно сформульоване поняття Моделі дозволить нам уникнути багатьох підводних каменів.
Проблема стану програми (State problem)
Визначимо що таке Стан (State). У більшості випадків стан розуміється як те, що в даний момент показано на екрані, наприклад "Стан завантаження контенту", коли View відображає ProgressBar.
Ми орієнтуємося на стан UI. стан інтерфейсу. І в цьому криється суть. Давайте подивимося на код вище (який йде до використання PersonsModel). Ви можете помітити, що станом UI управляє Presenter. Типова робота відбувається і в паттерне MVVM.
Але хотілося б розділити реалізації паттерна MVVM на два підходи: перший це Android data binding і другий за коштами RxJava. У першому варіанті стан зберігається в ViewModel.
Звичайно код не ідеальний і є, що додати. Сенс в тому що, в MVP і MVVM стан реалізується через Presenter або ViewModel.
З цього можна зробити наступні висновки:
- Бізнес логіка має свій стан, Presenter (або ViewModel) - своє (ви можете синхронізувати ці стани, вони схожі) і View також може мати стан.
- Presenter (або ViewModel) може мати безліч методів управління (які викликає View. Наприклад) і це нормально. Але таким же чином Presenter може мати безліч виходів (наприклад даних, методів для View. Таких як view.showLoading () або view.showError () в MVP). Все це безліч може привести до конфліктуючих станів View. Presenter і бізнес логіки, особливо коли робота відбувається з безліччю потоків.
Такі помилки дуже складно відловити і тим більше повторити.
Що якщо зробити одне джерело стану? Ми вже говорили про це на початку статті, коли обговорювали питання "Що таке модель?".
Здогадуєтеся? Модель реагує на стан. Як тільки я це зрозумів - багато проблем пов'язані зі станом (state) виявилися вирішені і презентер має тільки один вихід getView (). Render (PersonsModel). Це схоже на функцію f (x) = y (так само можливо безліч аргументів). І на відміну від програмного коду, математика не знає багів =)
Важливо розуміти, що таке «Модель» і як правильно її опеределить, тому що в підсумку Модель може вирішити «Проблему стану»
Зміна орієнтації екрану
Найпростіший шлях - це ігнорувати зміну орієнтації. Просто перезавантажувати всі дані після зміни орієнтації екрану. Це цілком обгрунтоване рішення. У більшості випадків ваш додаток працює в автономному режимі, тому дані надходять з локальної бази даних або з кешу. Тому завантаження даних відбувається дуже швидко після зміни орієнтації екрану. Таким чином, розробники почали використовувати MVP з «retaining presenter», щоб можна було відв'язати (і знищити) View під час зміни орієнтації екрану, тоді як Presenter залишається в пам'яті, а потім знову прив'язати View до Presenter. Подібне рішення існує і в MVVM з RxJava.
Але є проблема зі збереженням Presenter'а (або ViewModel). як відновити стан View в стан до повороту екрану, так щоб View і Presenter були в такому ж стані? У бібліотеці Mosby це вирішено через ViewState яка синхронізує стан бізнес логіки з View. Moxy. інша MVP бібліотека, реалізує цікавий підхід через "команди" для відновлення стану View.
Я впевнений що так само існують і інші рішення пов'язані з проблемою стану. І так, ці бібліотеки вирішують проблему стану, про яку ми вже говорили.
І знову маємо "Модель" яка відображає поточне "состоний" і тільки один метод "render" (getView (). Render (PersonsModel)). Рішення проблеми 2 практично зводиться до вирішення проблеми 1
Back stack навігація
Чи потрібно зберігати Presenter (ViewModel) коли View більше не використовується? Наприклад, якщо Fragment (View) був замінений на інший Fragment. тому що користувач перейшов на інший екран, то немає більш View прикріпленою до Presenter. Якщо View не прикріплений до Presenter. то очевидно вона не зможе оновитися до свіжих даних. А що якщо користувач вирішив повернутися назад на екран (наприклад натиснув кнопку назад)? Перезавантажувати дані або перевикористати Presenter. Це вже філософське питання =). Зазвичай при поверненні до попереднього вигляду користувач очікує побачити його таким яким він був (таким яким користувач його "залишив"). Це в більшості своїй "проблема відновлення стану View (див пункт 2). Рішення таке ж: модель відновлює стану шляхом виклику методу у ViewgetView (). Render (PersonsModel).
управління процесами
Поширеною помилкою в світі розробки під Android вважається те, що знищення процесів погана штука і нам потрібні бібліотеки які допоможуть зберегти і відновити стан після знищення процесу. Ну по-перше процес знищується тоді, коли ОС Android потрібно більше ресурсів для інших додатків або для збереження заряду батареї. Але цього ніколи не станеться, якщо додаток активно (на передньому плані) і користувач користується ним в цей момент. Якщо ж вам дійсно потрібно виконати тривалу завдання - використовуйте Service, як варіант, щоб повідомити операційної систему, що ваш додаток до цих пір активно використовується.
При знищенні процесу Android можна використовувати для здійснення методу onSaveInstanceState () для збереження стану. І знову Стан =) (State). Чи слід зберегти інформацію з View в Bundle. Чи має Presenter свій стан, яке теж слід зберегти в bundle. А що на рахунок стану бізнес логіки? Ми вже описали ці питання в пункту 1 - 3. Для цього нам потрібен клас Model. який відновлює / зберігає "все" стану. До слова, досить часто не потрібно нічого зберігати =)