Какие знаешь реализации ViewModel?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Реализации ViewModel в Android
В экосистеме Android существует несколько ключевых реализаций паттерна ViewModel, каждая из которых решает специфические задачи и используется в разных архитектурных контекстах.
1. AndroidX ViewModel (Jetpack ViewModel)
Это стандартная и наиболее распространённая реализация, часть библиотеки Android Jetpack. Она предназначена для хранения и управления UI-данными, связанными с жизненным циклом, способными переживать изменения конфигурации (например, поворот экрана).
Ключевые особенности:
- Привязка к жизненному циклу: Создается через
ViewModelProviderи привязывается кLifecycleOwner(обычноComponentActivityилиFragment). - Сохранение состояния: Может использовать
SavedStateHandleдля сохранения небольшого объема данных при временном уничтожении процесса системой. - Отсутствие ссылок на View: Позволяет избежать утечек памяти, так как не содержит прямых ссылок на
Activity,FragmentилиView.
// Пример использования в Activity или Fragment
class MyViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() {
private val _uiState = MutableStateFlow<UiState>(UiState.Loading)
val uiState: StateFlow<UiState> = _uiState.asStateFlow()
fun loadData() {
viewModelScope.launch {
_uiState.value = UiState.Success(repository.fetchData())
}
}
}
// Создание ViewModel
private val viewModel: MyViewModel by viewModels {
MyViewModelFactory(savedStateHandle = createSavedStateHandle())
}
2. MutableViewModel (или кастомные базовые реализации)
Часто в проектах создают собственную базовую реализацию ViewModel для добавления общих функциональностей, таких как:
- Единая обработка ошибок.
- Управление состоянием загрузки.
- Интеграция с навигацией или аналитикой.
- Упрощенная работа с
StateFlow/SharedFlow.
// Пример абстрактной базовой ViewModel
abstract class BaseViewModel<State : Any, Event : Any> : ViewModel() {
private val _state = MutableStateFlow<State?>(null)
val state: StateFlow<State?> = _state.asStateFlow()
private val _events = MutableSharedFlow<Event>()
val events: SharedFlow<Event> = _events.asSharedFlow()
protected fun setState(newState: State) {
_state.value = newState
}
protected suspend fun sendEvent(event: Event) {
_events.emit(event)
}
// Общая логика очистки подписок
override fun onCleared() {
super.onCleared()
// Освобождение ресурсов
}
}
3. HiltViewModel
Это специализированная реализация для работы с Hilt (библиотекой для dependency injection от Google). Аннотация @HiltViewModel позволяет внедрять зависимости прямо в конструктор ViewModel, а Hilt автоматически создает необходимые Factory.
Преимущества:
- Упрощенное создание
ViewModelс зависимостями. - Автоматическое управление временем жизни зависимостей (
@ViewModelScoped). - Интеграция с
SavedStateHandle.
@HiltViewModel
class ProfileViewModel @Inject constructor(
private val userRepository: UserRepository,
private val analytics: AnalyticsService,
savedStateHandle: SavedStateHandle
) : ViewModel() {
// Логика ViewModel с автоматически внедренными зависимостями
}
4. ViewModel в MVI/MVVM архитектурах
В этих архитектурных подходах ViewModel часто реализуется с определенной ролью:
- В MVI (Model-View-Intent):
ViewModelвыступает как редуктор, обрабатывающий интенты (намерения) от View и возвращающий новое состояние. - В MVVM (Model-View-ViewModel):
ViewModelявляется посредником между Model и View, предоставляя наблюдаемые данные и команды.
// Упрощенный пример MVI-подхода
class SearchViewModel : ViewModel() {
// Intent как sealed class
sealed class Intent {
data class QueryChanged(val query: String) : Intent()
object SearchClicked : Intent()
}
// State
data class State(val query: String = "", val results: List<Item> = emptyList())
private val _state = MutableStateFlow(State())
val state: StateFlow<State> = _state.asStateFlow()
fun processIntent(intent: Intent) {
when (intent) {
is Intent.QueryChanged -> _state.update { it.copy(query = intent.query) }
Intent.SearchClicked -> performSearch()
}
}
}
5. KMP-ViewModel (для Kotlin Multiplatform)
С развитием Kotlin Multiplatform появились реализации ViewModel, которые могут использоваться в общем коде (shared module). Например, библиотека moko-mvvm от IceRock или экспериментальная поддержка в kotlinx.coroutines.
Особенность: Эти реализации абстрагируются от Android-специфичных классов, предоставляя аналогичный API для iOS и других платформ.
Сравнительная таблица
| Реализация | Основное назначение | Ключевая особенность |
|---|---|---|
| AndroidX ViewModel | Управление UI-данными с учетом жизненного цикла | Интеграция с Jetpack, SavedStateHandle |
| HiltViewModel | Внедрение зависимостей в ViewModel | Автоматическое создание Factory через Hilt |
| MVI/MVVM ViewModel | Архитектурные паттерны | Четкое разделение состояний, интентов и событий |
| KMP ViewModel | Кроссплатформенная разработка | Работа в общем коде Kotlin Multiplatform |
Критерии выбора реализации
- Для большинства Android-проектов — используйте стандартную AndroidX ViewModel, часто в сочетании с Hilt для инъекции зависимостей.
- При сложной бизнес-логике — рассмотрите кастомную базовую
ViewModelили реализацию в стиле MVI для лучшей предсказуемости состояния. - Для кроссплатформенных проектов — оцените KMP-совместимые решения, если требуется разделять логику между Android и iOS.
- При использовании Clean Architecture —
ViewModelобычно реализуется как часть Presentation Layer, взаимодействуя с Use Cases и Domain Layer.
Важное замечание: Независимо от выбранной реализации, ViewModel не должна содержать ссылки на Android-контекст, View или другие объекты, связанные с UI-потоком. Её задача — подготовка данных для отображения и обработка логики, связанной с UI, но не манипуляция UI-элементами напрямую.