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

Можно ли использовать enum для ограниченного набора состояний?

1.2 Junior🔥 221 комментариев
#Kotlin основы#Архитектура и паттерны

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

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

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

Как ViewModel остается жить после смерти Activity

ViewModel остаётся жить после destroy Activity благодаря ViewModelStore и ViewModelProvider. ViewModel не уничтожается вместе с Activity при изменении конфигурации (поворот экрана) или других причинах уничтожения Activity. Это критично для сохранения состояния приложения.

Как это работает

// Activity уничтожается и создаётся заново
class MainActivity : AppCompatActivity() {
    private val viewModel: MainViewModel by viewModels()
    
    // viewModel живёт дольше Activity!
}

Механизм жизни ViewModel

Activity создаётся → ViewModelStore создаётся
           ↓
    viewModel создаётся (хранится в ViewModelStore)
           ↓
    Activity destroy (конфигурационные изменения)
           ↓
    ViewModelStore ОСТАЁТСЯ живым!
           ↓
    Activity создаётся заново
           ↓
    viewModel достаётся из старого ViewModelStore
           ↓
    Activity destroy (по-настоящему)
           ↓
    ViewModelStore уничтожается → ViewModel.onCleared()

ViewModelStore — ключ к долголетию

ViewModelStore — это компонент, который хранит ViewModel'ки и не привязан напрямую к Activity.

// Внутреннее устройство (упрощённо)
class ViewModelStore {
    private val store: MutableMap<String, ViewModel> = mutableMapOf()
    
    fun put(key: String, viewModel: ViewModel) {
        store[key] = viewModel
    }
    
    fun get(key: String): ViewModel? = store[key]
    
    fun clear() {
        for (viewModel in store.values) {
            viewModel.clear()  // Вызывает onCleared()
        }
        store.clear()
    }
}

ViewModelProvider — фабрика для создания ViewModel

// Когда ты пишешь:
private val viewModel: MainViewModel by viewModels()

// На самом деле происходит:
val viewModel = ViewModelProvider(this)
    .get(MainViewModel::class.java)

// ViewModelProvider ищет ViewModel в ViewModelStore:
// 1. Есть ли уже такой ViewModel в хранилище?
// 2. Если да → верни существующий
// 3. Если нет → создай новый и сохрани в ViewModelStore

Где живёт ViewModelStore

// ViewModelStore в ComponentActivity (родитель AppCompatActivity)
open class ComponentActivity : AppCompatActivity {
    private var viewModelStore: ViewModelStore? = null
    
    fun getViewModelStore(): ViewModelStore {
        if (viewModelStore == null) {
            viewModelStore = ViewModelStore()
        }
        return viewModelStore!!
    }
}

Почему ViewModel выживает при поворотах экрана

Когда экран поворачивается:

  1. Activity уничтожается (onDestroy вызывается)
  2. Activity создаётся заново (onCreate вызывается)
  3. НО ViewModelStore НЕ уничтожается!
class MainActivity : AppCompatActivity() {
    private val viewModel: MainViewModel by viewModels()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // При повороте экрана:
        // Первый раз: viewModel создаётся в ViewModelStore
        // Второй раз (после поворота): viewModel достаётся из ViewModelStore
        
        println(viewModel.hashCode())  // Один и тот же объект!
    }
}

// Тест
fun testViewModelSurvival() {
    val firstHashCode = viewModel.hashCode()
    // Поворот экрана (Activity уничтожается и создаётся)
    val secondHashCode = viewModel.hashCode()
    
    assertEquals(firstHashCode, secondHashCode)  // PASS!
}

Жизненный цикл ViewModel

class MainViewModel : ViewModel() {
    init {
        println("ViewModel создана")  // Один раз при первом создании
    }
    
    override fun onCleared() {
        println("ViewModel очищена")  // Один раз при уничтожении Activity
        // Очистка ресурсов, отписка от событий
    }
}

// Поворот экрана:
// 1. Activity destroy → onDestroy() Activity
// 2. Activity create → onCreate() Activity
// 3. ViewModel НЕ создаётся заново (выводит только один раз "ViewModel создана")
// 4. Activity destroy (по-настоящему) → onCleared() ViewModel

Сохранение состояния в ViewModel

class MainViewModel : ViewModel() {
    private val _uiState = MutableStateFlow("initial")
    val uiState: StateFlow<String> = _uiState.asStateFlow()
    
    fun updateState(newState: String) {
        _uiState.value = newState
    }
}

// Activity
class MainActivity : AppCompatActivity() {
    private val viewModel: MainViewModel by viewModels()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // При повороте экрана состояние СОХРАНИТСЯ!
        lifecycleScope.launch {
            viewModel.uiState.collect { state ->
                updateUI(state)
            }
        }
    }
}

Отличие от savedInstanceState

// savedInstanceState — сохраняется в onSaveInstanceState()
override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
    outState.putString("key", "value")
}

// ViewModel — просто живёт в памяти, не сохраняется на диск
// Поэтому ViewModel ТЕРЯЕТСЯ при:
// 1. Force kill приложения
// 2. Перезагрузка устройства
// 3. Смерть процесса из-за нехватки памяти

// Поэтому используй SavedStateHandle для сохранения на диск:
class MainViewModel(
    private val savedStateHandle: SavedStateHandle
) : ViewModel() {
    val state: StateFlow<String> = savedStateHandle
        .getStateFlow("state", "initial")
}

Когда ViewModel уничтожается

  1. На повороте экрана — НЕ уничтожается (выживает)
  2. При Back нажатии — уничтожается (Activity finish)
  3. При Force Stop приложения — уничтожается
  4. При нехватке памяти — может быть уничтожена (но ViewModelStore очищается)
// Проверка когда ViewModel уничтожается
class MainViewModel : ViewModel() {
    override fun onCleared() {
        // Вызывается когда Activity finish (Back нажата)
        // ИЛИ Activity полностью уничтожена
        super.onCleared()
        cleanup()
    }
}

Правила работы с ViewModel

  1. ViewModel = состояние, а не логика
  2. ViewModel > SavedInstanceState (для простого состояния)
  3. SavedStateHandle для стойкого сохранения
  4. onCleared() для очистки ресурсов (отписка, отмена Coroutines)

Ответ: ViewModel живёт дольше Activity благодаря ViewModelStore, которые хранит ViewModel отдельно от жизненного цикла Activity. При поворотах экрана Activity уничтожается, но ViewModelStore остаётся, поэтому ViewModel выживает и переиспользуется.

Можно ли использовать enum для ограниченного набора состояний? | PrepBro