You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: university/4-icerock-basics/mvvm.md
+56-98Lines changed: 56 additions & 98 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -26,51 +26,51 @@ sidebar_position: 6
26
26
27
27
## moko-mvvm
28
28
29
-
Для использования MVVM мы реализовали библиотеку [moko-mvvm](https://github.com/icerockdev/moko-mvvm). Главное, что мы стремились достичь при ее реализации, это использование оригинальных классов JetPack `ViewModel` и `LiveData` со стороны Android, чтобы продолжить использовать существующие в Android интеграции с данными классами (включая логику хранения `ViewModel` в `ViewModelStore` чтобы переживать смену конфигурации). Для iOS стороны (и других платформ тоже) классы `ViewModel` и `LiveData` были реализованы нами, в более простом виде чем в Android (так как только в Android есть сложный жизненный цикл компонентов с пересозданием). По сути классы `ViewModel` и `LiveData` являются expect классами с разными actual реализациями на платформах.
29
+
Для использования MVVM мы реализовали библиотеку [moko-mvvm](https://github.com/icerockdev/moko-mvvm). Главное, что мы стремились достичь при ее реализации, это использование оригинальных классов JetPack `ViewModel` и `StateFlow` со стороны Android, чтобы продолжить использовать существующие в Android интеграции с данными классами (включая логику хранения `ViewModel` в `ViewModelStore` чтобы переживать смену конфигурации). Для iOS стороны (и других платформ тоже) классы `ViewModel` и `StateFlow` были реализованы нами, в более простом виде чем в Android (так как только в Android есть сложный жизненный цикл компонентов с пересозданием). По сути классы `ViewModel` и `StateFlow` являются expect классами с разными actual реализациями на платформах.
30
30
31
31
Для знакомства с библиотекой посмотрите материалы на странице в базе знаний - [moko-mvvm](../../learning/libraries/moko/moko-mvvm).
32
32
33
-
### Привязка LiveData к UI
33
+
### Привязка StateFlow к UI
34
34
35
-
В библиотеке также содержатся готовые методы для привязки `LiveData` к UI элементам, по аналогии с методами, которые были использованы нами в [статье про State](../../learning/state). Данные методы доступны и для Android и для iOS, а поэтому в большинстве случаев вам не потребуется писать вручную привязку каждого типа данных к каждому UI элементу.
35
+
В библиотеке также содержатся готовые методы для привязки `StateFlow` к UI элементам, по аналогии с методами, которые были использованы нами в [статье про State](../../learning/state). Данные методы доступны и для Android и для iOS, а поэтому в большинстве случаев вам не потребуется писать вручную привязку каждого типа данных к каждому UI элементу.
36
36
37
-
Привязкой UI к `LiveData` называется binding, и основано на использовании метода `bind`:
Для `iOS` добавим функцию `bindToUIToolbarVisible` для связи `UIToolbar` c `LiveData<KotlinBoolean>` (на `iOS` из общего кода вместо `Boolean` приходит `KotlinBoolean`) вот как это будет выглядеть:
142
+
Для `iOS` добавим функцию `bindToUIToolbarVisible` для связи `UIToolbar` c `CStateFlow<KotlinBoolean>` (на `iOS` из общего кода вместо `Boolean` приходит `KotlinBoolean`) вот как это будет выглядеть:
Важно, в методах биндинга должна быть только привязка `liveData` к объекту `UI`, никакой логики быть не должно!
155
-
Вся логика должна быть во `ViewModel`, если нужно как-то преобразовать значение `liveData`, делайте это там.
154
+
Важно, в методах биндинга должна быть только привязка `flow` к объекту `UI`, никакой логики быть не должно!
155
+
Вся логика должна быть во `ViewModel`, если нужно как-то преобразовать значение `flow`, делайте это там.
156
156
157
157
### MvvmActivity и MvvmFragment
158
158
В moko-mvvm реализованы абстрактные классы [MvvmFragment](https://github.com/icerockdev/moko-mvvm/blob/b4b2ed1a86451bd303aa0733ecd776be96c6f455/mvvm-viewbinding/src/main/kotlin/dev/icerock/moko/mvvm/viewbinding/MvvmEventsFragment.kt) и [MvvmActivity](https://github.com/icerockdev/moko-mvvm/blob/b6f2630df03bbd405e5659d85ea7df03f38e5dc7/mvvm-viewbinding/src/main/kotlin/dev/icerock/moko/mvvm/viewbinding/MvvmActivity.kt), наследуясь от которых вы:
@@ -235,7 +235,6 @@ class TestFragment : MvvmFragment<TestFragmentBinding, AuthViewModel>() {
235
235
236
236
Разберем несколько подходов для передачи событий от `ViewModel` на UI:
237
237
- используя `Flow`
238
-
- используя `EventsDispatcher` из [moko-mvvm](https://github.com/icerockdev/moko-mvvm)
239
238
- используя `Flow` вместе с [moko-kswift](https://github.com/icerockdev/moko-kswift)
240
239
241
240
#### Flow
@@ -266,90 +265,49 @@ sealed interface Action {
266
265
В Kotlin-мире мы получим ошибку при компиляции, надо будет добавить в `when` обработку еще одного объекта - нового, который только что добавили во `ViewModel`.
267
266
А на iOS компилятор нам ничего не подскажет, потому что новый объект будет обрабатываться в ветке `else`. Из-за этого, логика перехода на iOS нарушится. Поиск ошибки может занять некоторое время, в зависимости от знаний разработчика.
268
267
269
-
Чтобы не сталкиваться с этим на практике мы долгое время использовали другой подход - с помощью `EventsDispatcher` из [moko-mvvm](https://github.com/icerockdev/moko-mvvm). Разберемся, как он работает.
268
+
Чтобы не сталкиваться с этим на практике мы используем другой подход - с помощью `Channel`. Разберемся, как он работает
270
269
271
-
#### EventsDispatcher
270
+
###Передача Action с помощью Channel
272
271
273
-
С этим подходом нужно разобраться, потому что на многих наших проектах сейчас используется именно он.
274
-
`EventDispatcher` - это класс с одной единственной задачей - гарантировать доставку события и вызов его обработчика на UI, после сигнала от `ViewModel`.
275
-
276
-
Во `ViewModel` объявляется интерфейс с методами, реализация которых ей нужна на платформе, например, метод для перехода на какой-нибудь экран:
277
-
278
-
```kotlin
279
-
interfaceEventsListener {
280
-
funrouteToMainPage()
281
-
}
282
-
```
283
-
284
-
Далее, все что остается сделать, чтобы вызвать событие на `UI` - это получить во `ViewModel` объект `eventsDispatcher` и, когда пора переходить на главный экран, послать платформе это событие простым вызовом метода:
272
+
Во view model добавляем канал и события для передачи:
viewModel.actions.subscribe { [weakself] action in
299
+
guardletself=self,
300
+
let action = action else { return }
301
+
let actionKs =SimpleViewModelActionKs(action)
302
+
switch actionKs {
303
+
case .showMessage(let data):
304
+
...
305
+
case .routeToBack:
306
+
...
339
307
}
340
308
}
341
309
```
342
310
343
-
За счет интерфейса обе платформы знают, какой набор действий должны поддерживать.
344
-
Если во `ViewModel` нужно будет добавить еще одно событие, и мы забудем реализовать его на какой-нибудь из платформ, компилятор выделит, что отсутствует реализация метода интерфейса.
345
-
346
-
:::warning
347
-
348
-
В `dispatchEvent` нельзя передавать лямбду из общего кода, например, для установки действия по кнопке в [AlertDialog](https://developer.android.com/reference/android/app/AlertDialog). Нельзя этого делать потому, что на Android мы не сможем ее никуда сохранить, поэтому при пересоздании экрана она пропадет.
349
-
Если вам нужно установить чему-либо на платформе действие - делайте соответствующий метод во `ViewModel`.
350
-
351
-
:::
352
-
353
311
#### Flow c moko-kswift
354
312
Мы уже рассмотрели, с какими проблемами мы столкнулись бы, если бы использовали `Flow` в общем коде.
355
313
Разберем теперь, как можно решить эти проблемы, начнем с отсутствия типов у `Flow` на iOS.
Благодаря переносу всей логики приложения в общий код мы получаем более удобное и простое API библиотеки для интеграции на платформы. Мы знаем что есть, например, ряд `ViewModel`-ей, в которых есть `LiveData` на которые нужно подписаться и `EventsDispatcher`события от которого нужно обрабатывать. Все передаваемые на UI данные уже подготовлены к отображению и не требуют дополнительной обработки.
328
+
Благодаря переносу всей логики приложения в общий код мы получаем более удобное и простое API библиотеки для интеграции на платформы. Мы знаем что есть, например, ряд `ViewModel`-ей, в которых есть `StateFlow` на которые нужно подписаться и события, которые нужно обрабатывать. Все передаваемые на UI данные уже подготовлены к отображению и не требуют дополнительной обработки.
371
329
372
330
Вот некоторый список преимуществ, которые мы получаем за счет использования `ViewModel`-ей в общем коде:
0 commit comments