Activity
Activity
Основной компонент Android, представляющий экран приложения. Она управляет UI, жизненным циклом и взаимодействием с пользователем.
class MainActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
override fun onStart() {
super.onStart()
}
override fun onResume() {
super.onResume()
}
override fun onPause() {
super.onPause()
}
override fun onStop() {
super.onStop()
}
override fun onDestroy() {
super.onDestroy()
}
}
onCreate
Вызывается при создании Activity
. В нём задаётся интерфейс и начальная логика.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
onStart
Вызывается, когда Activity
становится видимой для пользователя.
override fun onStart() {
super.onStart()
dataObserver.startObserving()
}
onResume
Вызывается, когда Activity
переходит в активное состояние и готова взаимодействовать с пользователем.
override fun onResume() {
super.onResume()
startRefreshingData()
}
onPause
Вызывается, когда Activity
уходит на второй план, но всё ещё частично видима.
override fun onPause() {
super.onPause()
pauseAnimations()
}
onStop
Вызывается, когда Activity
перестаёт быть видимой.
override fun onStop() {
super.onStop()
dataObserver.stopObserving()
}
onDestroy
Вызывается перед уничтожением Activity
.
override fun onDestroy() {
super.onDestroy()
cleanupResources()
}
isFinishing
Используется для проверки, находится ли активность в процессе завершения. Он возвращает true
, если активность была запущена для завершения (например, из-за вызова finish()
или по завершению жизненного цикла Activity
), и false, если активность все еще активно работает. Вы можете использовать isFinishing()
перед выполнением операций, которые требуют, чтобы активность была активна, чтобы избежать потенциальных ошибок, связанных с обращением к UI, если активность уже завершена.
override fun onPause() {
super.onPause()
if (!isFinishing) {
// Выполняем действия только если Activity не завершается
}
}
Launch Modes
standart
Режим запуска Activity
по умолчанию в Android. В этом режиме каждый раз, когда Activity
запускается, создается новый экземпляр этой Activity
, и каждый новый экземпляр помещается в стек задач. При этом Activity
может быть создано несколько раз, даже если уже существует экземпляр этой Activity
в стеке. Каждый новый экземпляр Activity
в режиме standard получает уникальный task и back stack, что позволяет сохранить состояние и историю переходов, обеспечивая независимость между различными экземплярами Activity
.
<activity
android:name=".MainActivity"
android:launchMode="standart" />
singleTop
Режим запуска Activity
, при котором только один экземпляр Activity
может быть в стеке задач. Если Activity
с singleTop
уже находится на вершине стека, новая попытка её запуска не создаст новый экземпляр, а вызовет метод onNewIntent()
. Если Activity
не на вершине стека, будет создан новый экземпляр.
<activity
android:name=".MainActivity"
android:launchMode="singleTop" />
singleTask
Режим запуска Activity
, при котором в одной задаче может существовать только один экземпляр Activity
. Если Activity
с singleTask
уже существует, она будет показана, и все Activity
в текущем стеке выше её будут удалены; если нет, она будет создана в новой задаче.
<activity
android:name=".MainActivity"
android:launchMode="singleTask" />
singleInstance
Устанавливает, что Activity
будет существовать только в одном экземпляре в своей собственном, отдельном стеке задач (task
). Это означает, что если такая Activity
уже существует, то новая задача не создаст её экземпляр, а вместо этого вернёт существующий экземпляр.
<activity
android:name=".MainActivity"
android:launchMode="singleInstance" />
singleInstancePerTask
Когда активность запускается в режиме singleInstancePerTask
, система создает единственный экземпляр этой Activity
для каждой задачи. Это означает, что если активность уже существует в другой задаче, новый экземпляр не будет создан. Вместо этого пользователь будет перенаправлен к существующему экземпляру. В отличие от других режимов запуска (например, singleTask
), этот режим обеспечивает, что Activity
всегда будет единственной в своей задаче, и только одна задача может содержать этот экземпляр. Если Activity
вызывается из другой задачи, она будет перемещена в фокус, а не создана заново.
• Добавлен в Android 12 (API 31).
<activity
android:name=".MainActivity"
android:launchMode="singleInstancePerTask" />
taskAffinity
Определяет, к какой задаче (task) принадлежит активность. По умолчанию все активности приложения имеют одинаковую задачу, но с помощью taskAffinity
можно задать для активности принадлежность к другой задаче. Task (Задача) — это стек активностей, с которыми взаимодействует пользователь. Если активность имеет другую taskAffinity
, она может быть запущена в отдельной задаче или присоединиться к задаче другого приложения с таким же значением taskAffinity
. Это полезно, когда нужно контролировать, как активности взаимодействуют с задачами и как они отображаются в списке последних приложений.
• Работает в связке с launchMode
активности (например, singleTask
, singleTop
). Например, если taskAffinity
изменён, а launchMode
задан как singleTask
, активность будет запускаться в своей задаче и перезапускаться, если она уже существует.
• Хорошее объяснение на StackOverflow.
<activity
android:name=".MainActivity"
android:taskAffinity="" />
<activity
android:name=".SettingsActivity"
android:taskAffinity="com.example.differenttask" />
TaskStackBuilder
Позволяет создавать и управлять стеком задач для запуска активностей. Он помогает организовать задачи и их историю, чтобы обеспечить правильное поведение навигации при запуске новых активностей. TaskStackBuilder
упрощает создание и запуск стека активностей, который будет отображаться в правильном порядке, когда пользователь возвращается к предыдущим активностям.
// Создаем TaskStackBuilder для запуска нового Activity
val stackBuilder = TaskStackBuilder.create(context)
// Добавляем Intent для нового Activity
stackBuilder.addNextIntentWithParentStack(newIntent)
// Запускаем Activity
stackBuilder.startActivities()
addNextIntent
Добавляет новый Intent
в back stack без учета родительских экранов.
addNextIntentWithParentStack
Добавляет новый Intent
в back stack с учетом иерархии родительских экранов.
ActivityManager
Системный сервис в Android, который управляет жизненным циклом активностей и задач, а также отслеживает состояние процессов в системе. ActivityManager
отслеживает все активные, видимые и фоновые активности на устройстве.
val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
getRunningTasks
Возвращает список задач, которые в настоящее время запущены. Можно указать максимальное количество задач, которые нужно вернуть.
val runningTasks = activityManager.getRunningTasks(10)
getRunningAppProcesses
Возвращает список всех запущенных процессов в системе.
val runningAppProcesses = activityManager.runningAppProcesses
getRecentTasks
Возвращает список недавних задач, которые можно открыть из недавнего меню приложений.
val recentTasks = activityManager.getRecentTasks(10, ActivityManager.RECENT_IGNORE_UNAVAILABLE)
getRunningServices
Возвращает список всех запущенных служб.
val runningServices = activityManager.getRunningServices(10)
getMemoryInfo
Заполняет объект ActivityManager.MemoryInfo
информацией о текущем состоянии памяти.
val memoryInfo = ActivityManager.MemoryInfo()
activityManager.getMemoryInfo(memoryInfo)
getProcessMemoryInfo
Возвращает информацию о потреблении памяти для процессов с указанными идентификаторами процессов (PID).
val processMemoryInfo = activityManager.getProcessMemoryInfo(intArrayOf(pid))
killBackgroundProcesses
Завершает все фоновые процессы, связанные с указанным пакетом.
activityManager.killBackgroundProcesses("com.example.myapp")
getAppTasks
Возвращает список задач, связанных с текущими приложениями.
val appTasks = activityManager.appTasks
getLauncherActivities
Возвращает список активностей, которые могут быть запущены из лаунчера.
val launcherActivities = activityManager.launcherActivities
OnBackPressedDispatcher
Управляет обработкой нажатия кнопки «Назад» (Back) в приложении. Позволяет разным частям приложения регистрировать свои обработчики, которые будут вызваны при нажатии кнопки. Пришел на замену методу onBackPressed
.
class MainActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Регистрируем обработчик нажатия кнопки "Назад"
onBackPressedDispatcher.addCallback(this, object: OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
// Логика при нажатии кнопки "Назад"
println("Кнопка 'Назад' нажата")
}
})
}
}
Вопросы на собесе (33)
Lifecycle (14)
- Жизненный цикл Activity?
onCreate()
→onStart()
→onResume()
→onPause()
→onStop()
→onDestroy()
- Какие методы жизненного цикла Activity вызываются при переходе на следующую Activity?
• Переходим вперед:
onPause()
→onStop()
• Возвращаемся обратно:
onStart()
→onResume()
- В какой момент жизненного цикла Activity виден экран?
onStart()
- Какие методы жизненного цикла Activity вызываются при отображении DialogFragment?
Жизненный цикл не изменяется.
- Какие методы жизненного цикла Activity вызываются при отображении/закрытии permission dialog?
onPause()
↔onResume()
- Какие методы жизненного цикла Activity вызываются при переходе в task manager (recent menu)?
Жизненный цикл не изменяется.
- Какие методы жизненного цикла Activity вызываются при смахивании приложения?
onPause()
→onStop()
→onDestroy()
- Какие методы жизненного цикла Activity вызываются при сворачивании/разворачивании приложения?
• При сворачивании:
onPause()
→onStop()
• При разворачивании:
onStart()
→onResume()
- Какие методы жизненного цикла Activity вызываются при смене ориентации экрана (изменении конфигурации)?
• Activity пересоздается:
onPause()
→onStop()
→onDestroy()
→onCreate()
→onStart()
→onResume()
• При сохранении состояния:
onPause()
→onStop()
→onSaveInstanceState()
→onDestroy()
→onCreate()
→onStart()
→onRestoreInstanceState()
→onResume()
- Если запустить Activity2 которая частично перекрывает Activity1, какие коллбэки вызовутся у Activity1?
onPause()
- Когда onDestroy вызовется без onPause и onStop?
finish()
вonCreate()
- В каком случае вызов onDestroy() не гарантирован?
В случае внезапного завершения процесса системы, например, если система убивает приложение для освобождения ресурсов, когда недостаточно памяти. В таких ситуациях система может не вызвать методы жизненного цикла, включая
onDestroy()
.
- Как изменилось поведение onResume и onPause в Android 10?
В Android 10 добавлена поддержка foldables и изменено поведение коллбэков
onResume()
иonPause()
в режиме multi-window: все видимые активити находятся в состоянии resumed, а Activity, с которой взаимодействует пользователь, называется topmost resumed. Введен коллбэкonTopResumedActivityChanged(isTopResumed: Boolean)
для различия между resumed и topmost resumed Activity.
- В каком из случаев вызов onDestroy() в Activity не гарантирован?
• Переворот экрана.
• Вызов метода
finish()
.• Приложение свернуто, система ”убила” процесс приложения.
- Жизненный цикл Activity?
Launch Modes (8)
- Какие есть Launch Modes у Activity?
standart
singleTop
singleTask
singleInstance
- Для чего нужно задавать параметр launchMode у Activity?
Параметр
launchMode
задает, как будет вести себя новаяActivity
при запуске, управляя созданием экземпляров в стеке задач и предотвращая дублирование.
- Как работает launchMode SingleTop?
SingleTop
запускаетActivity
только в том случае, если она не находится на вершине стека. ЕслиActivity
уже открыта, система вызывает методonNewIntent()
существующего экземпляра, передавая ему новые намерения, что позволяет обновить данные без создания нового экземпляра.
- Как работает launchMode SingleInstance?
SingleInstance
создает уникальный экземплярActivity
в своем собственном стекe задач. Если такаяActivity
уже существует, при запуске вызоветсяonNewIntent()
.
- Есть стек из Activity A-B-C-A-B, запускаем Activity C c launchMode SingleTop, что произойдет в системе?
У
Activity
C вызовется методonNewIntent()
.
- Ты находишься внутри Activity A и опять вызываешь Activity A c launch mode SingleTop, что произойдет в Activity A?
Вместо создания нового экземпляра будет переиспользован текущий, и вызовется метод
onNewIntent()
.
- Есть Activity А, ты запустил Activity B с launch mode SingleTask и в ней произошел краш, что произойдет с приложением и что увидит юзер?
Приложение завершится, и пользователь увидит системное сообщение о том, что приложение остановилось. Activity A также будет уничтожена вместе с приложением.
- Эффект какого из launch mode Activity описан ниже? Если экземпляр Activity уже существует на вершине текущего Task, новый экземпляр не будет сгенерирован, а новые данные для Activity будут оправлены через onNewlntent().
•
singleTask
•
singleTop
•
singlelnstance
•
standard
- Какие есть Launch Modes у Activity?
Другие (11)
- Как сделать Activity главной?
Указать для нее в
AndroidManifest
intent-фильтр сaction
MAIN иcategory
LAUNCHER.
- Что будет если сделать 2 Activity главными?
Обе будут отображаться в списке приложений, и пользователь сможет выбрать, какую из них запустить.
- Как пережить поворот экрана? (Смену конфигурации)
• Переопределить
onSaveInstanceState(Bundle outState)
и восстановить вonCreate()
.• Использовать
ViewModel
для сохранения данных.• Добавить
configChanges
в манифест (не рекомендуется).
- Есть ли смысл сохранять данные если поддерживаем только портретную ориентацию?
Да. В приложении может произойти сбой. Существуют другие способы изменения конфигурации (смена локали).
- Как запустить стек из нескольких Activity?
Через
TaskStackBuilder
в виде стека одним вызовом.
- Как запустить Activity в отдельном процессе?
Указать атрибут
android:process
в манифесте для этойActivity
.
- Чем Activity отличается от Fragment?
Мы легко можем управлять стеком фрагментов. Со стеком активностей возникают проблемы: мы не можем гарантировать их порядок, активити может создастся по интенту другим приложением.
- Если не вызовем setContentView или поместим туда null что увидим?
Цвет установленный в
windowBackground
.
- Как запустить приложение без Activity?
Через
BroadcastReceiver
, который реагирует на системные события (например, загрузку устройства), или черезService
, запущенный при старте системы. В этом случае интерфейса у приложения не будет, но фоновые задачи могут выполняться.
- Как закрыть сразу n активити в стеке?
Удалить все
Activity
выше запущенной в стеке можно через флагflags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK
.
- Можно ли создать приложение без Activity?
• Да, можно. (Приложение Android WebView. Системный сервис для просмотра web-страниц)
• Нет, у приложения всегда должна быть хотя бы одна активити.
- Как сделать Activity главной?