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

Какие знаешь инструменты Jetpack ViewModel для работы с данными и состоянием?

1.0 Junior🔥 162 комментариев
#UI и вёрстка

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

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

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

Инструменты Jetpack ViewModel для работы с данными и состоянием

ViewModel — это ключевой компонент архитектурного паттерна MVVM в Android, предназначенный для хранения и управления UI-данными с учетом жизненного цикла компонентов (Activity/Fragment). Он предоставляет ряд инструментов и методов для эффективной работы с данными и состоянием приложения.

1. LiveData

LiveData — это наблюдаемый контейнер данных, который учитывает жизненный цикл, что позволяет автоматически обновлять UI при изменении данных. ViewModel часто использует LiveData для публикации данных, на которые могут подписываться UI-компоненты.

class MyViewModel : ViewModel() {
    private val _userName = MutableLiveData<String>()
    val userName: LiveData<String> get() = _userName
    
    fun updateName(name: String) {
        _userName.value = name
    }
}

Преимущества LiveData:

  • Автоматическая отписка при уничтожении наблюдателя (Activity/Fragment)
  • Отсутствие утечек памяти
  • Актуальные данные при возобновлении UI (например, после поворота экрана)

2. StateFlow и SharedFlow

В современной разработке рекомендуется использовать корутины Kotlin вместе с StateFlow и SharedFlow для реактивного программирования. Они предоставляют более гибкий и мощный способ управления состоянием.

class MyViewModel : ViewModel() {
    private val _uiState = MutableStateFlow<UiState>(UiState.Loading)
    val uiState: StateFlow<UiState> = _uiState.asStateFlow()
    
    init {
        viewModelScope.launch {
            _uiState.value = UiState.Success(loadData())
        }
    }
    
    sealed class UiState {
        object Loading : UiState()
        data class Success(val data: List<String>) : UiState()
        data class Error(val message: String) : UiState()
    }
}

Отличия Flow от LiveData:

  • Flow — часть экосистемы корутин, поддерживает сложные асинхронные операции
  • StateFlow — всегда имеет значение и кеширует его (аналог LiveData)
  • SharedFlow — не хранит значение по умолчанию, подходит для событий

3. SavedStateHandle

SavedStateHandle позволяет сохранять и восстанавливать данные при временном уничтожении процесса (например, при нехватке памяти). Это особенно полезно для сохранения состояния UI.

class SavedStateViewModel(
    private val savedStateHandle: SavedStateHandle
) : ViewModel() {
    companion object {
        private const val SEARCH_QUERY_KEY = "search_query"
    }
    
    var searchQuery: String
        get() = savedStateHandle.get<String>(SEARCH_ERY_KEY) ?: ""
        set(value) = savedStateHandle.set(SEARCH_QUERY_KEY, value)
    
    // Автоматическая привязка к LiveData
    val queryLiveData = savedStateHandle.getLiveData<String>(SEARCH_QUERY_KEY)
}

4. ViewModelScope

Каждый ViewModel имеет собственную CoroutineScopeviewModelScope, которая автоматически отменяется при очистке ViewModel. Это упрощает управление корутинами и предотвращает утечки памяти.

class NetworkViewModel : ViewModel() {
    fun fetchData() {
        viewModelScope.launch {
            try {
                val result = repository.loadData()
                // Обработка результата
            } catch (e: Exception) {
                // Обработка ошибок
            }
        }
    }
}

5. Потоки данных с трансформациями

ViewModel предоставляет методы для трансформации LiveData:

  • Transformations.map — преобразует значение LiveData
  • Transformations.switchMap — переключается на другой LiveData в зависимости от исходного значения
  • MediatorLiveData — объединяет несколько источников LiveData
class UserViewModel(private val repository: UserRepository) : ViewModel() {
    private val userIdLiveData = MutableLiveData<String>()
    
    val userLiveData: LiveData<User> = Transformations.switchMap(userIdLiveData) { id ->
        repository.getUserById(id)
    }
    
    fun setUserId(id: String) {
        userIdLiveData.value = id
    }
}

6. AndroidViewModel

AndroidViewModel — подкласс ViewModel, который получает контекст приложения в конструкторе. Используется, когда необходим доступ к ресурсам или системным сервисам.

class MyAndroidViewModel(application: Application) : AndroidViewModel(application) {
    private val context = getApplication<Application>().applicationContext
    
    fun getAppVersion(): String {
        return context.packageManager
            .getPackageInfo(context.packageName, 0)
            .versionName
    }
}

Практические рекомендации

  1. Разделение ответственности:

    • ViewModel отвечает за подготовку данных для UI
    • Не должен содержать ссылок на View, Context или Activity
    • Сложную логику выносите в UseCase или Domain-слой
  2. Тестирование:

    • ViewModel легко тестировать благодаря отделению от Android-компонентов
    • Используйте Mock-объекты для зависимостей
  3. Архитектурные подходы:

    • MVI (Model-View-Intent) с использованием StateFlow для одностороннего потока данных
    • State Hoisting — поднятие состояния в родительский ViewModel
    • Декларативный UI с Jetpack Compose

Ключевой принцип: ViewModel должен хранить только данные, необходимые для отображения UI, и содержать логику для их подготовки. Бизнес-логика должна находиться в отдельном слое (доменном или use case). Это обеспечивает тестируемость, поддерживаемость и соблюдение принципа единой ответственности.

Современный подход предполагает использование корутин с StateFlow/SharedFlow для реактивного программирования, но LiveData остается хорошим выбором для простых случаев или при работе с XML-разметкой. Выбор конкретного инструмента зависит от сложности приложения, команды и используемых архитектурных паттернов.

Какие знаешь инструменты Jetpack ViewModel для работы с данными и состоянием? | PrepBro