#ArchitectureComponents #ViewModel
Should I use Jetpack ViewModel?
Архитектура MVVM на основе Jetpack на сегодня довольно популярна в Android разработке. Вы задумывались так ли много проблем решает ViewModel из Jetpack?
Автор в своей статье приводит доводы, которые заставят вас задуматься так ли все просто и помогут найти проблемы
Should I use Jetpack ViewModel?
Архитектура MVVM на основе Jetpack на сегодня довольно популярна в Android разработке. Вы задумывались так ли много проблем решает ViewModel из Jetpack?
Автор в своей статье приводит доводы, которые заставят вас задуматься так ли все просто и помогут найти проблемы
Glureau
Should I use Jetpack ViewModel? - Grégory Lureau
Adding a new library to a production project should always be done with extra care.
#Hilt #ViewModel
Using Hilt’s ViewModelComponent
В Dagger 2.31 появился ViewModelComponent и соответствующий Scope. Для того чтобы переиспользовать сущности за пределами жизни Activity у нас существует теперь 2 scope:
Using Hilt’s ViewModelComponent
В Dagger 2.31 появился ViewModelComponent и соответствующий Scope. Для того чтобы переиспользовать сущности за пределами жизни Activity у нас существует теперь 2 scope:
@ViewModelScoped и @ActivityRetainedScoped#Compose #ViewModel #Flow
Better handling states between ViewModel and Composable
В статье рассказывается как лучше соединить изменение состояния из ViewModel в Compose на основе Coroutines Flow
Better handling states between ViewModel and Composable
В статье рассказывается как лучше соединить изменение состояния из ViewModel в Compose на основе Coroutines Flow
#ViewModel #Dagger
Способы инжектить ViewModel с помощью Dagger: что может пойти не так
Рецепт как соединить DI через Dagger с Arch Components, чтобы делать inject ViewModel и зависимостей в них
Способы инжектить ViewModel с помощью Dagger: что может пойти не так
Рецепт как соединить DI через Dagger с Arch Components, чтобы делать inject ViewModel и зависимостей в них
#compose #viewmodel #navigation
Jetpack Compose navigation architecture with ViewModels
Вариант организации навигации с Jetpack Compose, который предлагает Google и как туда вписать ViewModel
Jetpack Compose navigation architecture with ViewModels
Вариант организации навигации с Jetpack Compose, который предлагает Google и как туда вписать ViewModel
#viewmodel #livedata #flow
Kotlin’s Flow in ViewModels: it’s complicated
Разбор реактивных подходов в ViewModel: LiveData, Flow, StateFlow, сравнение и почему LiveData ещё может быть актуальна
Kotlin’s Flow in ViewModels: it’s complicated
Разбор реактивных подходов в ViewModel: LiveData, Flow, StateFlow, сравнение и почему LiveData ещё может быть актуальна
#compose #viewmodel
Compose UI and the death of ViewModel
Рассуждения на тему, что при использовании Jetpack Compose ViewModel больше не нужна т.к. не её жизненный цикл привязан к жизни Activity/Fragment.
Моё мнение, что нужно правильнее организовать хранение ViewModel и привязать его к правильному scope Compose функции. Например, уже сейчас есть привязка к графу навигации
Compose UI and the death of ViewModel
Рассуждения на тему, что при использовании Jetpack Compose ViewModel больше не нужна т.к. не её жизненный цикл привязан к жизни Activity/Fragment.
Моё мнение, что нужно правильнее организовать хранение ViewModel и привязать его к правильному scope Compose функции. Например, уже сейчас есть привязка к графу навигации
#viewmodel
Don't let ViewModel knew about framework level dependencies
Пример почему использовать что-то из Android SDK, за исключение JDK классов, является плохим и создаст вам проблемы в тестах и как абстрагироваться от Android Framework
Don't let ViewModel knew about framework level dependencies
Пример почему использовать что-то из Android SDK, за исключение JDK классов, является плохим и создаст вам проблемы в тестах и как абстрагироваться от Android Framework
#compose #viewmodel
ViewModels using Compose: MutableStateFlows or MutableStates?
Руководство как организовать сохранение состояния между пересозданиями процесса, когда вы используете Compose в центре которого состояние. Автор использует ViewModel + SavedStateHandle.
ViewModels using Compose: MutableStateFlows or MutableStates?
Руководство как организовать сохранение состояния между пересозданиями процесса, когда вы используете Compose в центре которого состояние. Автор использует ViewModel + SavedStateHandle.
Сравнение подходов между хранением состояния в. ViewModel в видео одного объекте или множества свойств внутри ViewModel. Подробности тут (EN, 4 мин, ссылка без VPN). Делитесь в комментариях какой подход выбираете вы и почему
#viewmodel #architecture
#viewmodel #architecture
👍19
Обновления Lifecycle.2.8.0-alpha03 заслуживают отдельного поста
👉 ViewModel.viewModelScope теперь можно перегрузить через конструктор. Сможете свои параметры CoroutineContext задать
👉 Артефакт
👉 Прошла миграция с Java class на Kotlin KClass
#jetpackupdate #kmp #jetpack #viewmodel
👉 ViewModel.viewModelScope теперь можно перегрузить через конструктор. Сможете свои параметры CoroutineContext задать
👉 Артефакт
lifecycle-viewmodel теперь мультиплатформенный, а также все API в них ViewModel, ViewModelStore, ViewModelStoreOwner, и ViewModelProvider 👉 Прошла миграция с Java class на Kotlin KClass
#jetpackupdate #kmp #jetpack #viewmodel
🔥28👍11
Обновления библиотек Jetpack Lifecycle 2.8.0
Lifecycle
👉 LocalLifecycleOwner из Compose переехал в
👉 Новые Composable API dropUnlessResumed и dropUnlessStarted что позволяет лямбду вызывать только когда LifecycleOwner достигнет состояния Resumed/Started соотвественно и не будет вызывать когда выйдет из него. Например, полезно для навигации
👉 LifecycleStartEffect и LifecycleResumeEffect бросают ошибку если не задать key. По аналоги с DisposableEffect
👉 API
ViewModel
👉 ViewModel теперь позволяет передать произвольный CoroutineScope при создании. Полезно для тестов и не только
👉 ViewModel переписали на Kotlin и перешли с Closable на AutoClosable из Kotlin
👉 API
👉
👉 Для всех таргетов не Android должна быть обязательна указана фабрика для
LiveData
👉 Переписали NullSafeMutableLiveData
#lifecycle #viewmodel #compose #kmp
Lifecycle
👉 LocalLifecycleOwner из Compose переехал в
lifecycle-runtime-compose👉 Новые Composable API dropUnlessResumed и dropUnlessStarted что позволяет лямбду вызывать только когда LifecycleOwner достигнет состояния Resumed/Started соотвественно и не будет вызывать когда выйдет из него. Например, полезно для навигации
👉 LifecycleStartEffect и LifecycleResumeEffect бросают ошибку если не задать key. По аналоги с DisposableEffect
👉 API
Lifecycle, LifecycleOwner, LifecycleObserver, Lifecycle.State, Lifecycle.Event и LifecycleRegistry теперь являются частью мультиплатформенных модулейViewModel
👉 ViewModel теперь позволяет передать произвольный CoroutineScope при создании. Полезно для тестов и не только
👉 ViewModel переписали на Kotlin и перешли с Closable на AutoClosable из Kotlin
👉 API
ViewModel, ViewModelStore, ViewModelStoreOwner и ViewModelProvider теперь являются частью мультиплатформенных модулей👉
ViewModelProvider.NewInstanceFactory и ViewModelProvider.AndroidViewModelFactory доступны только на Android👉 Для всех таргетов не Android должна быть обязательна указана фабрика для
ViewModelLiveData
👉 Переписали NullSafeMutableLiveData
#lifecycle #viewmodel #compose #kmp
❤14👍10
Библиотека Jetpack SavedState получила поддержку 👩💻 KMP (пока в альфе). Поддерживаются Android, iOS, Linux, Mac и JVM. Появился новый тип SavedState, который является alias-ом для Bundle в Android, а на других платформах - Map<String, Any>. Работа происходит через SavedStateReader и SavedStateWriter, обёрнутые Kotlin DSL.
VIewModel также получила поддержку KMP Saved State в новой альфе
#kmp #jetpack #viewmodel
VIewModel также получила поддержку KMP Saved State в новой альфе
#kmp #jetpack #viewmodel
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥48👍10
Полный разбор ViewModel, что позволит вам прокачаться в знаниях, узнать глубже API, которое используете, и ответить на вопросы на собеседованиях как Senior. Весь разбор на реальном коде в IDE
Что в видео:
👉 как удобно использовать
👉 Создание нестандартного ViewModelStore
👉 создание собственных фабрик
👉 как ViewModel пережить смерть процесса, а не только поворот экрана
Видео доступно по подписке в Telegram и на Boosty (лучше тут), либо единоразовая покупка тут
#AndroidBroadcast #viewmodel #jetpack #kmp
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥62👍6❤3
#viewmodel #jetpack #jetpackupdate #android
Please open Telegram to view this post
VIEW IN TELEGRAM
👍47
Как правильно работать с MutableStateFlow внутри ViewModel и из вне
Если вы пишите под Android и используете MVVM и корутины, то у вас будет подобный код
По всем рекомендациям мы не должны давать наружу изменяемое состояние и все изменения должны делать только через методы. Самый простой вариант - указание отдельного публичного типа.
Каждое обращение к свойства state будет приводить к созданию новому экземпляру
Больше подобных моих материалов и подборка интересных статей, книг, видео есть в Базе Знаний Android разработчика
#android #kotlin #coroutines #jetpack #viewmodel #AndroidBroadcast #БазаЗнаний
Если вы пишите под Android и используете MVVM и корутины, то у вас будет подобный код
class YourViewModel() : ViewModel() {
val state = MutableStateFlow<State>(State.Initial)
}По всем рекомендациям мы не должны давать наружу изменяемое состояние и все изменения должны делать только через методы. Самый простой вариант - указание отдельного публичного типа.
class YourViewModel() : ViewModel() {
private val _state = MutableStateFlow<State>(State.Initial)
val state: StateFlow<State>
get() = _state
}В Kotlin есть возможность указать разного типа для свойства и его field, но пока доступна только как экспериментальная. Использовать её в продакшен коде на текущем этапе жизни не рекомендуетсяС таким подходом мы закрыли через приведение типа на уровне свойства. Авторы Kotlin Coroutines позаботились о нас и сделали нашу жизнь проще с помощью функции asStateFlow(), который под капотом обернет
MutableStateFlow в ReadonlyStateFlow и вернёт его как StateFlow. Применяя оператор мы получим следующий код:class YourViewModel() : ViewModel() {
private val _state = MutableStateFlow<State>(State.Initial)
val state: StateFlow<State>
get() = _state.asStateFlow()
}Каждое обращение к свойства state будет приводить к созданию новому экземпляру
StateFlow, что является лишним, так как один StateFlow может иметь несколько коллекторов (подписчиков) на данные и никак не повлияет на работу, то можно сразу задавать свойство безе перегрузки get()class YourViewModel() : ViewModel() {
private val _state = MutableStateFlow<State>(State.Initial)
// Создаем StateFlow, предназначенный для получения
// состояния из вне ViewModel
val state = _state.asStateFlow()
}Больше подобных моих материалов и подборка интересных статей, книг, видео есть в Базе Знаний Android разработчика
#android #kotlin #coroutines #jetpack #viewmodel #AndroidBroadcast #БазаЗнаний
👍70 13🤯5❤1
Погружение в код реализации Jetpack ViewModel (EN, 5м)
Разбор как реализована Jetpack ViewModel после добавления поддержки KMP: код в класса, AutoClosable, viewModelScope
Для платных подписчиков на Boosty можно найти обзор всех фичей ViewModel, которые будут полезны вам
#android #kmp #jetpack #androidx #viewmodel #подкапотом
Разбор как реализована Jetpack ViewModel после добавления поддержки KMP: код в класса, AutoClosable, viewModelScope
Для платных подписчиков на Boosty можно найти обзор всех фичей ViewModel, которые будут полезны вам
#android #kmp #jetpack #androidx #viewmodel #подкапотом
👍19🤯2
В статье рассказывается в чем сложность с обработкой одноразовых событий, которые надо передать из ViewModel в UI.
Автор рассматривает способ через callback интерфейс в конструкторе ViewModel
@HiltViewModel
class MyViewModel @Inject constructor(
// inject the interface
private val toastMessages: ToastMessages,
) : ViewModel() {
fun doSomething() {
viewModelScope.launch {
try {
// execute async operation here
} catch (e: CustomException) {
// initiate a one-off event
toastMessages.showToast(e.localizedMessage)
}
}
}
}
🔗 Альтернативная ссылка на статью
#android #viewmodel #dagger #hilt
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13
Вот реальная история, как знание механики работы ViewModel спасло мне вечер 👇
У меня приложение на Compose и Jetpack Navigation 3 (работает на основе состояния Back Stack). Экран «Навигатор файлов» открывает папки рекурсивно: по сути это тот же экран, но с другими данными. Все данные — из одной и той же❗️ Баг: при переходе в папку навигация срабатывает, UI не меняется. Современные ИИ подсказали общие вещи, но не помогли — промты, видимо, подвели (тут мне ещё надо прокачать знания) 🙂
Вспомнил ключевой факт про архитектуру:
👉 Все
👉 В пределах одного
👉 Если нужно несколько экземпляров одного типа на одном owner’е — используем key.
Решение в одну строку — привязать ключ к ViewModel, связанный с текущей папкой:
Мини-чеклист, если ловите такой баг
👉 Один экран используется повторно с разными параметрами? → Нужен key.
👉 Меняется route, но owner тот же? → key обязателен.
👉 Используете Hilt/Koin? → У этих функций тоже есть параметр key (hiltViewModel(key=...), koinViewModel(key=...)).
👉 key должен детерминированно зависеть от входных данных (например, folderId).
👉 При навигации назад убедитесь, что ViewModel освобождается ожидаемо.
Ещё нюанс - если у вас сложная иерархия графов, проверьте, к какому
Рекомендую посмотреть мои видео по теме:
📹 Разбор Jetpack Navigation 3
🪙 Полный разбор Jetpack ViewModel в Android и Kotlin Multiplatform
#android #compose #androidjetpack #viewmodel #архитектура
У меня приложение на Compose и Jetpack Navigation 3 (работает на основе состояния Back Stack). Экран «Навигатор файлов» открывает папки рекурсивно: по сути это тот же экран, но с другими данными. Все данные — из одной и той же
ViewModel.Вспомнил ключевой факт про архитектуру:
👉 Все
ViewModel живут в ViewModelStore.👉 В пределах одного
ViewModelStoreOwner (Activity/Fragment/NavBackStackEntry) получение ViewModel по умолчанию идёт по типу.👉 Если нужно несколько экземпляров одного типа на одном owner’е — используем key.
Решение в одну строку — привязать ключ к ViewModel, связанный с текущей папкой:
@Composable
fun FileNavigator(
folderId: Id,
modifier: Modifier = Modifier,
) {
// новый folderId → новый экземпляр ViewModel → новый UI-стейт
val viewModel: FileNavigatorViewModel = viewModel(
key = "files(rootId='$folderId')"
)
// ...
}
Мини-чеклист, если ловите такой баг
👉 Один экран используется повторно с разными параметрами? → Нужен key.
👉 Меняется route, но owner тот же? → key обязателен.
👉 Используете Hilt/Koin? → У этих функций тоже есть параметр key (hiltViewModel(key=...), koinViewModel(key=...)).
👉 key должен детерминированно зависеть от входных данных (например, folderId).
👉 При навигации назад убедитесь, что ViewModel освобождается ожидаемо.
Ещё нюанс - если у вас сложная иерархия графов, проверьте, к какому
ViewModelStoreOwner вы реально привязаны.Рекомендую посмотреть мои видео по теме:
#android #compose #androidjetpack #viewmodel #архитектура
Please open Telegram to view this post
VIEW IN TELEGRAM
12👍86🤔10🤯5❤2🔥2
Google выпустила мажорное обновление библиотек Lifecycle. Этот релиз сфокусирован на улучшении интеграции с Compose.
rememberLifecycleOwner для ComposeНовый композабл позволяет создавать изолированные
LifecycleOwner внутри UI. Идеально для компонентов, которым нужно независимое управление состоянием — например, для HorizontalPager, где только активная страница должна быть в состоянии RESUMED.@Composable
fun MyComposable() {
val lifecycleOwner = rememberLifecycleOwner(
maxLifecycle = Lifecycle.State.RESUMED,
parentLifecycleOwner = LocalLifecycleOwner.current,
)
CompositionLocalProvider(
LocalLifecycleOwner provides lifecycleOwner
) {
// Дочерние композаблы теперь имеют собственный жизненный цикл
}
}
Новый артефакт
lifecycle-viewmodel-navigation3 предоставляет готовый декоратор для автоматической привязки ViewModel к отдельным экранам в Navigation 3.NavDisplay(
backStack = backStack,
entryDecorators = listOf(
rememberSaveableStateHolderNavEntryDecorator(),
rememberViewModelStoreNavEntryDecorator(), // Добавляем эту строку
),
entryProvider = entryProvider { /* ... */ }
)
Удобства для разработчиков:
👉 Идиоматичный Kotlin API для создания кастомных
CreationExtras CreationExtras {
this[MY_CUSTOM_KEY] = "myValue"
}
👉 Метод
savedStateHandle.saved() теперь нативно поддерживает nullable типы👉 Конструкторы SavedStateHandle помечены как
@VisibleForTesting⚠️ Важное изменение
Повышение
minSdk с API 21 до API 23 — убедитесь, что ваше приложение соответствует новым требованиям.#Jetpack #Lifecycle #Compose #Navigation #ViewModel #Kotlin
Please open Telegram to view this post
VIEW IN TELEGRAM
❤14🔥8🤯3👍2🙏1