← Назад к вопросам

Какие знаешь реализации ViewModel?

2.0 Middle🔥 251 комментариев
#Android компоненты#Архитектура и паттерны#Жизненный цикл и навигация

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Реализации 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

Критерии выбора реализации

  1. Для большинства Android-проектов — используйте стандартную AndroidX ViewModel, часто в сочетании с Hilt для инъекции зависимостей.
  2. При сложной бизнес-логике — рассмотрите кастомную базовую ViewModel или реализацию в стиле MVI для лучшей предсказуемости состояния.
  3. Для кроссплатформенных проектов — оцените KMP-совместимые решения, если требуется разделять логику между Android и iOS.
  4. При использовании Clean ArchitectureViewModel обычно реализуется как часть Presentation Layer, взаимодействуя с Use Cases и Domain Layer.

Важное замечание: Независимо от выбранной реализации, ViewModel не должна содержать ссылки на Android-контекст, View или другие объекты, связанные с UI-потоком. Её задача — подготовка данных для отображения и обработка логики, связанной с UI, но не манипуляция UI-элементами напрямую.