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

Как сохранить состояние всех действий в навигации

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

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

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

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

Сохранение состояния в Android Navigation Component

Сохранить состояние всех Activity в навигации можно через механизм ViewModel и SavedStateHandle, но для сохранения состояния самих фрагментов (которые являются основой современной навигации в Android) требуется особая настройка. Основная проблема заключается в том, что по умолчанию FragmentManager уничтожает неактивные фрагменты для освобождения памяти, теряя их состояние.

Ключевые подходы

1. Сохранение состояния через ViewModel + SavedStateHandle

Для сохранения простых данных (строки, примитивы) между конфигурационными изменениями и процессом смерти:

class MyViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() {
    companion object {
        private const val KEY_TEXT = "text_key"
    }
    
    val textLiveData = savedStateHandle.getLiveData<String>(KEY_TEXT)
    
    fun saveText(text: String) {
        savedStateHandle.set(KEY_TEXT, text)
    }
}

2. Включение сохранения состояния фрагментов в Navigation Component

Для сохранения всех фрагментов в back stack необходимо настроить FragmentManager. Вот основной метод:

// В вашей Activity или родительском фрагменте
supportFragmentManager.enableSaveStateHandling(true)

// ИЛИ при настройке Navigation Component
val navHostFragment = supportFragmentManager
    .findFragmentById(R.id.nav_host_fragment) as NavHostFragment

// Сохраняем состояние фрагментов в back stack
navHostFragment.childFragmentManager.enableSaveStateHandling(true)

Но важно отметить: В последних версиях Navigation Component (2.4.0+) сохранение состояния включено по умолчанию для фрагментов в back stack. Проверьте вашу версию:

// build.gradle
implementation 'androidx.navigation:navigation-fragment-ktx:2.5.3'
implementation 'androidx.navigation:navigation-ui-ktx:2.5.3'

3. Пользовательская реализация сохранения сложного состояния

Для сохранения сложных объектов (списков, кастомных классов):

class DetailFragment : Fragment() {
    private lateinit var viewModel: DetailViewModel
    private var complexData: MyComplexData? = null
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // Восстанавливаем состояние
        savedInstanceState?.let {
            complexData = it.getParcelable("complex_data")
        }
        
        viewModel = ViewModelProvider(this).get(DetailViewModel::class.java)
    }
    
    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        outState.putParcelable("complex_data", complexData)
    }
    
    // Для сохранения при уничтожении процесса
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewLifecycleOwner.lifecycleScope.launch {
            viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
                viewModel.state.collect { state ->
                    // Сохраняем в SavedStateHandle через ViewModel
                }
            }
        }
    }
}

Полное решение для сохранения состояния всей навигации

  1. Настройка NavHostFragment:
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        val navHostFragment = supportFragmentManager
            .findFragmentById(R.id.nav_host_fragment) as NavHostFragment
        
        // Важно: устанавливаем FragmentFactory для сохранения состояния
        navHostFragment.childFragmentManager
            .enableSaveStateHandling(true)
    }
}
  1. Использование ViewModel со SavedStateHandle для каждого фрагмента:
class SharedViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() {
    private val _navigationState = MutableStateFlow<NavigationState>(NavigationState.Default)
    val navigationState: StateFlow<NavigationState> = _navigationState.asStateFlow()
    
    fun saveNavigationState(state: NavigationState) {
        savedStateHandle.set("nav_state", state)
    }
    
    init {
        savedStateHandle.get<NavigationState>("nav_state")?.let {
            _navigationState.value = it
        }
    }
}
  1. Глобальное сохранение состояния через OnBackPressedCallback:
class MainActivity : AppCompatActivity() {
    private lateinit var appStateViewModel: AppStateViewModel
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        appStateViewModel = ViewModelProvider(this).get(AppStateViewModel::class.java)
        
        onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
            override fun handleOnBackPressed() {
                // Сохраняем текущее состояние перед возвратом
                saveCurrentFragmentsState()
                if (!supportFragmentManager.popBackStackImmediate()) {
                    finish()
                }
            }
        })
    }
    
    private fun saveCurrentFragmentsState() {
        val navHostFragment = supportFragmentManager
            .findFragmentById(R.id.nav_host_fragment) as? NavHostFragment
        navHostFragment?.let {
            // Сохраняем состояние каждого фрагмента в back stack
            it.childFragmentManager.fragments.forEach { fragment ->
                (fragment as? StateSaver)?.saveState()
            }
        }
    }
}

Рекомендации по архитектуре

  • Используйте Single Activity Architecture с Navigation Component
  • Храните навигационное состояние в SharedViewModel на уровне Activity
  • Для критичных данных используйте персистентное хранилище (Room, DataStore)
  • Тестируйте восстановление состояния через Developer Options → "Don't keep activities"
  • Избегайте хранения тяжелых объектов в бандлах, используйте идентификаторы и восстанавливайте данные из базы

Важное предупреждение: Сохранение состояния всех фрагментов может потребовать значительной памяти. Оценивайте необходимость сохранения каждого фрагмента индивидуально и реализуйте очистку ненужных состояний в onLowMemory().

Как сохранить состояние всех действий в навигации | PrepBro