Класс Activity – это важный компонент приложения Android, а способ запуска и объединения действий – фундаментальная часть модели приложения платформы. В отличие от парадигм программирования, в которых приложения запускаются с помощью метода main, система Android инициирует код в экземпляре Activity, вызывая определенные методы обратного вызова, которые соответствуют определенным этапам его жизненного цикла.
В этом документе описывается концепция действий и приводятся некоторые рекомендации по работе с ними. Дополнительную информацию о рекомендациях по архитектуре приложения вы можете найти в Руководстве по архитектуре приложений.
Концепция действий
В отличие от компьютеров, на мобильных устройствах взаимодействие пользователя с приложением не всегда начинается с одного и того же места. Путь пользователя часто начинается недетерминированно. Например, если вы откроете почтовое приложение с главного экрана, то увидите список писем. И наоборот, если вы используете приложение социальной сети, которое затем запускает ваше почтовое приложение, вы можете перейти непосредственно к экрану почтового приложения для составления электронного письма.
Для этого предназначен класс Activity. Когда одно приложение вызывает другое, вызывающее приложение вызывает действие в другом приложении, а не приложение как единое целое. Таким образом, действие служит точкой входа для взаимодействия приложения с пользователем. Вы реализуете действие как подкласс класса Activity.
Действие предоставляет окно, в котором приложение отрисовывает свой интерфейс. Обычно оно занимает весь экран, но может быть и меньше, а также располагаться поверх других окон.
Обычно одно действие в приложении указывается как основное действие, которое является первым экраном, появляющимся при запуске приложения пользователем. В современных приложениях Compose это единственное необходимое действие, поскольку оно размещает composable-функции в архитектуре с одним действием, а не владеет иерархией View. Вместо того чтобы в приложении было несколько действий для экранов, composable-функции в действии содержат несколько пунктов назначения навигации.
Чтобы использовать объекты activity в приложении, необходимо зарегистрировать информацию о них в манифесте приложения. Также рекомендуется изучить жизненный цикл объекта activity. Остальная часть этого документа посвящена этим темам.
Настройка манифеста
Чтобы приложение могло использовать действия, необходимо объявить их и некоторые их атрибуты в манифесте.
Заявить о действиях
Чтобы объявить действие, откройте файл манифеста и добавьте элемент <activity> в качестве дочернего для элемента <application>. Пример:
<manifest ... >
<application ... >
<activity android:name=".ExampleActivity" />
...
</application ... >
...
</manifest >
Единственный обязательный атрибут для этого элемента – android:name, который указывает имя класса действия. Вы также можете добавить атрибуты, определяющие характеристики действия, такие как ярлык, значок или тема пользовательского интерфейса. Дополнительную информацию об этих и других атрибутах можно найти в справочной документации по элементу <activity>.
Объявление фильтров intent
Фильтры намерений – это очень мощная функция платформы Android. Они позволяют запускать действия на основе не только явных, но и неявных запросов. Например, явный запрос может указывать системе "Запустить действие "Отправить письмо" в приложении Gmail". Неявный запрос, напротив, сообщает системе, что нужно запустить экран отправки электронного письма в любом действии, которое может выполнить эту задачу. Когда системный интерфейс спрашивает пользователя, какое приложение использовать для выполнения задачи, это работает фильтр интентов.
Чтобы воспользоваться этой функцией, объявите атрибут <intent-filter> в элементе <activity>. Определение этого элемента включает элемент <action> и, при необходимости, элемент <category> и/или элемент <data>. Эти элементы в совокупности определяют тип намерения, на которое может реагировать ваше действие. Например, в следующем фрагменте кода показано, как настроить действие, которое отправляет текстовые данные и электронные письма и получает запросы на выполнение этих действий от других действий:
<activity android:name=".ExampleActivity" android:icon="@drawable/app_icon">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SENDTO" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="mailto" />
</intent-filter>
</activity>
В этом примере элемент <action> указывает, что это действие отправляет данные. Если объявить элемент <category> как DEFAULT, то действие сможет получать запросы на запуск. Элемент <data> указывает тип данных, которые может отправлять это действие. В следующем фрагменте кода показано, как вызвать описанное выше действие, чтобы составить электронное письмо:
fun composeEmail(addresses: Array<String>, subject: String) {
val intent = Intent(Intent.ACTION_SENDTO).apply {
data = Uri.parse("mailto:") // Only email apps handle this.
putExtra(Intent.EXTRA_EMAIL, addresses)
putExtra(Intent.EXTRA_SUBJECT, subject)
}
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
}
}
Если вы хотите, чтобы ваше приложение было автономным и не позволяло другим приложениям активировать его действия, вам не нужны другие фильтры интентов. Activity, которые вы не хотите делать доступными для других приложений, не должны иметь фильтров интентов, и вы можете запускать их самостоятельно с помощью явных интентов. Подробнее о том, как действия могут реагировать на интенты…
Обработка входящих намерений
В примере ниже показано, как управлять жизненным циклом объекта activity при обработке нескольких типов намерений: отправки одного текстового сообщения, одного изображения и нескольких изображений. Направляя эти различные входные данные через централизованную функцию handleIntent, он гарантирует, что действия ACTION_SEND и ACTION_SEND_MULTIPLE будут правильно проанализированы и делегированы ViewModel для реактивного обновления пользовательского интерфейса.
class ExampleActivity : ComponentActivity() {
private val viewModel: MyViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
handleIntent(intent)
setContent {
ComposeApp(viewModel)
}
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
handleIntent(intent)
}
private fun handleIntent(intent: Intent?) {
when (intent?.action) {
Intent.ACTION_SEND -> {
if ("text/plain" == intent.type) {
intent.getStringExtra(Intent.EXTRA_TEXT)?.let {
viewModel.handleText(it) // Update UI to reflect text being shared
}
} else if (intent.type?.startsWith("image/") == true) {
(intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java))?.let {
viewModel.handleImage(it) // Update UI to reflect image being shared
}
}
}
Intent.ACTION_SEND_MULTIPLE -> {
if (intent.type?.startsWith("image/") == true) {
intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM, Uri::class.java)?.let {
viewModel.handleMultipleImages(it) // Update UI to reflect multiple images being shared
}
} else {
// Handle other types
}
}
else -> {
// Handle other intents
}
}
}
}
Объявление разрешений
С помощью тега <activity> в манифесте можно указать, какие приложения могут запускать определенные действия. Родительское действие не может запустить дочернее, если у них разные разрешения в манифесте. Если вы объявляете элемент <uses-permission> для родительского действия, у каждого дочернего действия должен быть соответствующий элемент <uses-permission>.
Например, если ваше приложение хочет использовать гипотетическое приложение SocialApp, чтобы опубликовать запись в социальной сети, SocialApp должно определить разрешение, которое должно иметь вызывающее его приложение:
<manifest>
<activity android:name="...."
android:permission="com.google.socialapp.permission.SHARE_POST"
/>
Чтобы ваше приложение могло вызывать SocialApp, оно должно соответствовать набору разрешений, заданному в манифесте SocialApp:
<manifest>
<uses-permission android:name="com.google.socialapp.permission.SHARE_POST" />
</manifest>
Дополнительную информацию о разрешениях и безопасности можно найти в контрольном списке по безопасности.
Управление жизненным циклом объекта activity
В течение своего жизненного цикла действие проходит через несколько состояний. Для обработки переходов между состояниями используется серия обратных вызовов. Ниже приведены сведения об этих обратных вызовах. В приложении Compose не рекомендуется напрямую подключаться к этим обратным вызовам. Вместо этого используйте Lifecycle API, чтобы отслеживать изменения статуса. Подробнее об интеграции жизненного цикла с Compose…
onCreate
Этот обратный вызов необходимо реализовать. Он срабатывает, когда система создает действие. В реализации должны инициализироваться основные компоненты действия. Например, здесь приложение должно создавать представления и связывать данные со списками.
В приложении Compose используйте этот обратный вызов, чтобы настроить хост-компонент с помощью setContent, как показано ниже:
class MyActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Text(text = stringResource(id = R.string.greeting))
}
}
}
После завершения onCreate всегда вызывается onStart.
onStart
Когда onCreate завершает работу, действие переходит в состояние Started и становится видимым для пользователя. Этот обратный вызов содержит то, что составляет окончательную подготовку действия к выходу на передний план и началу взаимодействия.
onResume
Система вызывает этот обратный вызов непосредственно перед тем, как действие начинает взаимодействовать с пользователем. В этот момент объект activity находится вверху стека и принимает все действия пользователя. Большинство основных функций приложения реализовано в методе onResume.
Обратный вызов onPause всегда следует за onResume.
onPause
Система вызывает onPause, когда объект activity теряет фокус и переходит в состояние Paused. Это происходит, например, когда пользователь нажимает кнопку "Назад" или "Недавние". Когда система вызывает onPause для вашего действия, это технически означает, что оно все ещё частично видно, но чаще всего указывает на то, что пользователь покидает его и скоро оно перейдет в состояние Stopped или Resumed.
Действие в состоянии Paused может продолжать обновлять пользовательский интерфейс, если пользователь ожидает этого. Примеры: экран навигационной карты или медиапроигрыватель. Даже если такие действия теряют фокус, пользователь ожидает, что их пользовательский интерфейс продолжит обновляться.
Не используйте onPause для сохранения данных приложения или пользователя, выполнения сетевых вызовов или транзакций базы данных. Подробнее о том, как сохранять данные…
После завершения выполнения onPause следующим обратным вызовом будет onStop или onResume в зависимости от того, что происходит после перехода операции в состояние "Приостановлено".
onStop
Система вызывает метод onStop, когда объект activity больше не виден пользователю. Это может произойти, если действие удаляется, начинается новое действие или существующее действие переходит в состояние Resumed и перекрывает остановленное действие. Во всех этих случаях остановленное действие больше не будет видно.
Следующим система вызывает либо метод onRestart, если пользователь возвращается к работе с операцией, либо метод onDestroy, если операция полностью завершается.
onRestart
Система вызывает этот обратный вызов, когда операция в состоянии Stopped должна перезапуститься. onRestart восстанавливает состояние действия с момента его остановки.
За этим обратным вызовом всегда следует onStart.
onDestroy
Система вызывает этот обратный вызов перед уничтожением действия.
Это последний обратный вызов, который получает действие. Метод onDestroy обычно используется, чтобы освободить все ресурсы действия, когда оно или содержащий его процесс уничтожается.
В этом разделе приводится лишь краткое описание. Подробную информацию о жизненном цикле объекта activity и его обратных вызовах можно найти в разделе Жизненный цикл объекта activity.