onBackPressed() устарел в Android 13. Как правильно обрабатывать нажатие кнопки "Назад"?
Почему onBackPressed() устарел?
Google отказался от прямого переопределения onBackPressed() в Activity, потому что этот метод не учитывает современную архитектуру Android, где навигация часто управляется фрагментами и Jetpack Navigation. Новый API — OnBackPressedDispatcher — позволяет добавлять обработчики нажатия "Назад" на любом уровне: в Activity, Fragment, View или даже в отдельном компоненте, и они будут работать согласованно.
Основные компоненты нового API
- OnBackPressedDispatcher — диспетчер, который управляет всеми обработчиками нажатия "Назад". Он есть у каждой Activity и Fragment.
- OnBackPressedCallback — абстрактный класс, который вы расширяете, чтобы определить своё поведение при нажатии "Назад".
Как использовать в Activity
Вместо переопределения onBackPressed() в Activity, нужно зарегистрировать callback через onBackPressedDispatcher. Пример с диалогом подтверждения:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Регистрируем callback
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
// Показываем диалог
AlertDialog.Builder(this@MainActivity)
.setTitle("Выход")
.setMessage("Вы уверены, что хотите выйти?")
.setPositiveButton("Да") { _, _ ->
// Если пользователь подтвердил — вызываем isEnabled = false и повторно диспатчим
isEnabled = false
onBackPressedDispatcher.onBackPressed()
}
.setNegativeButton("Нет", null)
.show()
}
})
}
}
Важные моменты:
- Параметр
trueв конструктореOnBackPressedCallbackозначает, что callback активен. Если поставитьfalse, он будет игнорироваться. - Внутри
handleOnBackPressed()вы можете выполнить свою логику. Если нужно завершить Activity стандартным образом (как при обычном нажатии "Назад"), вы должны временно отключить свой callback (isEnabled = false) и вызватьonBackPressedDispatcher.onBackPressed()снова — тогда сработает следующий обработчик в цепочке (обычно системный, который закрывает Activity). - Метод
addCallbackпринимаетLifecycleOwner(this — Activity) — это автоматически удалит callback, когда Activity будет уничтожена.
Как использовать во Fragment
Во Fragment регистрация callback происходит аналогично, но через requireActivity().onBackPressedDispatcher:
class MyFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
// Ваша логика, например, показать Snackbar
Snackbar.make(view, "Нажмите ещё раз для выхода", Snackbar.LENGTH_SHORT).show()
}
})
}
}
Обратите внимание: используется viewLifecycleOwner, а не this (lifecycle фрагмента). Это гарантирует, что callback будет активен только пока существует View фрагмента, и автоматически удалится при его уничтожении.
Работа с Jetpack Navigation
Если вы используете Jetpack Navigation, то в большинстве случаев вообще не нужно писать свой callback — библиотека сама обрабатывает нажатие "Назад" для переходов между экранами. Но если нужно перехватить нажатие на конкретном экране (например, чтобы показать диалог "Сохранить изменения?"), делается это так же, как во Fragment выше.
Итог
Новый API — это гибкая система, которая позволяет добавлять обработчики нажатия "Назад" на любом уровне иерархии. Главные правила:
- Не переопределяйте
onBackPressed()в Activity. - Используйте
onBackPressedDispatcher.addCallback()с подходящим LifecycleOwner. - Если нужно выполнить действие и потом передать управление дальше — временно отключите свой callback.
Альтернативный подход: использование OnBackPressedCallback в ViewModel
Если вы придерживаетесь MVVM и хотите, чтобы логика обработки нажатия "Назад" была в ViewModel (например, для сохранения данных или проверки изменений), можно передать callback во ViewModel через фабрику или напрямую.
class MyViewModel(private val onBackPressedCallback: OnBackPressedCallback) : ViewModel() {
fun onSaveAndExit() {
// Сохраняем данные
onBackPressedCallback.isEnabled = false
onBackPressedCallback.handleOnBackPressed() // или вызвать диспетчер
}
}
Но будьте осторожны: ViewModel переживает поворот экрана, а callback привязан к жизненному циклу Activity/Fragment. Лучше хранить callback в Activity/Fragment и вызывать методы ViewModel из handleOnBackPressed().
Простой способ для быстрого перехода
Если вам нужно просто заменить старое поведение без сложной логики, можно оставить вызов super.onBackPressed() внутри нового callback, но это не рекомендуется, так как теряется гибкость. Лучше сразу привыкать к новому API.
Также можно использовать библиотеку androidx.activity:activity-ktx, которая предоставляет расширения для работы с OnBackPressedDispatcher — она уже включена в стандартные зависимости Android-проектов.
Ответов пока нет.
Войдите чтобы оставить ответ