Введение в деятельность

Класс Activity является важнейшим компонентом Android-приложения, и способ запуска и организации Activity — это фундаментальная часть модели приложения платформы. В отличие от парадигм программирования, в которых приложения запускаются с помощью метода main , система Android инициализирует код в экземпляре Activity , вызывая определенные методы обратного вызова, соответствующие определенным этапам его жизненного цикла.

В этом документе представлено понятие действий, а затем даны краткие рекомендации по работе с ними. Для получения дополнительной информации о лучших практиках проектирования архитектуры приложения см. Руководство по архитектуре приложений .

Концепция деятельности

Взаимодействие с мобильным приложением отличается от взаимодействия с настольным приложением тем, что оно не всегда начинается в одном и том же месте. Вместо этого, путь пользователя часто начинается непредсказуемо. Например, если вы открываете почтовое приложение с главного экрана, вы можете увидеть список писем. В отличие от этого, если вы используете приложение социальной сети, которое затем запускает ваше почтовое приложение, вы можете сразу перейти к экрану почтового приложения для написания письма.

Класс Activity разработан для обеспечения этой парадигмы. Когда одно приложение вызывает другое, вызывающее приложение вызывает активность в другом приложении, а не само приложение как единое целое. Таким образом, активность служит точкой входа для взаимодействия приложения с пользователем. Активность реализуется как подкласс класса Activity .

Activity предоставляет окно, в котором приложение отображает свой пользовательский интерфейс. Это окно обычно заполняет весь экран, но может быть меньше экрана и располагаться поверх других окон.

Как правило, в приложении одна активность указывается как основная активность , которая является первым экраном, появляющимся при запуске приложения пользователем. В современных приложениях Compose это единственная необходимая активность, поскольку она размещает компоненты в рамках единой архитектуры активности, а не имеет иерархии представлений. Вместо того чтобы приложение имело несколько активностей для экранов, компоненты в этой активности размещают несколько пунктов навигации.

Для использования Activity в вашем приложении необходимо зарегистрировать информацию о них в манифесте приложения, и рекомендуется учитывать жизненные циклы Activity. Остальная часть этого документа посвящена этим темам.

Настройка манифеста

Для того чтобы ваше приложение могло использовать активности, необходимо объявить сами активности и некоторые их атрибуты в манифесте.

Объявить о деятельности

Чтобы объявить активность, откройте файл манифеста и добавьте элемент <activity> в качестве дочернего элемента элемента <application> . Например:

<manifest ... >
  <application ... >
      <activity android:name=".ExampleActivity" />
      ...
  </application ... >
  ...
</manifest >

Единственным обязательным атрибутом для этого элемента является android:name , который указывает имя класса активности. Вы также можете добавить атрибуты, определяющие характеристики активности, такие как метка, значок или тема пользовательского интерфейса. Для получения дополнительной информации об этих и других атрибутах см. справочную документацию по элементу <activity> .

Объявить фильтры намерений

Фильтры намерений — это очень мощная функция платформы 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)
    }
}

Если вы планируете, что ваше приложение будет самодостаточным и не позволит другим приложениям активировать его действия, вам не понадобятся никакие другие фильтры намерений. Действия, которые вы не хотите предоставлять другим приложениям, не должны иметь фильтров намерений, и вы можете запускать их самостоятельно, используя явные намерения. Для получения дополнительной информации о том, как ваши действия могут реагировать на намерения, см. раздел «Намерения и фильтры намерений» .

Обработка входящих намерений

В следующем примере показан шаблон управления жизненным циклом активности при обработке нескольких типов намерений: отдельные текстовые сообщения, отдельные изображения и несколько массивов изображений. Передавая эти разнообразные входные данные через централизованную функцию 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>

Для получения дополнительной информации о правах доступа и безопасности в целом см. Контрольный список безопасности .

Управление жизненным циклом деятельности

В течение своего жизненного цикла активность проходит через ряд состояний. Для обработки переходов между состояниями используется ряд коллбэков. В следующих разделах эти коллбэки будут описаны. В приложении Compose не рекомендуется напрямую подключаться к этим коллбэкам. Вместо этого используйте 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

Система вызывает этот коллбэк непосредственно перед тем, как активность начинает взаимодействовать с пользователем. В этот момент активность находится на вершине стека активностей и перехватывает весь пользовательский ввод. Большая часть основной функциональности приложения реализована в методе onResume .

Функция обратного вызова onPause всегда следует за onResume .

onPause

Система вызывает onPause когда активность теряет фокус и переходит в состояние «Приостановлено». Это состояние возникает, например, когда пользователь нажимает кнопку «Назад» или «Недавние». Когда система вызывает onPause для вашей активности, это технически означает, что ваша активность все еще частично видна, но чаще всего это указывает на то, что пользователь покидает активность, и вскоре она перейдет в состояние «Остановлено» или «Возобновлено».

Активность, находящаяся в состоянии «Приостановлено», может продолжать обновлять пользовательский интерфейс, если пользователь ожидает этого обновления. Примерами такой активности могут служить экран с картой навигации или воспроизведение медиаплеера. Даже если такие активности теряют фокус, пользователь ожидает, что его пользовательский интерфейс продолжит обновляться.

Не следует использовать onPause для сохранения данных приложения или пользователя, выполнения сетевых запросов или операций с базой данных. Информацию о сохранении данных см. в разделе «Сохранение и восстановление временного состояния пользовательского интерфейса» .

После завершения выполнения onPause , следующим обратным вызовом будет либо onStop , либо onResume , в зависимости от того, что произойдет после того, как активность перейдет в состояние Paused.

onStop

Система вызывает onStop когда активность перестаёт быть видимой для пользователя. Это может произойти из-за уничтожения активности, запуска новой активности или перехода существующей активности в состояние «Возобновлено» и перекрытия остановленной активности. Во всех этих случаях остановленная активность вообще перестаёт быть видимой.

Следующий вызов функции обратного вызова, который производит система, — это либо onRestart , если активность возвращается для взаимодействия с пользователем, либо onDestroy если активность полностью завершается.

при перезапуске

Система вызывает этот обратный вызов, когда активность в состоянии «Остановлено» собирается перезапуститься. onRestart восстанавливает состояние активности с момента её остановки.

За этим обратным вызовом всегда следует onStart .

onDestroy

Система вызывает этот обратный вызов перед уничтожением активности.

Этот коллбэк является последним, который получает активность. onDestroy обычно используется для обеспечения освобождения всех ресурсов активности при её уничтожении или уничтожении процесса, содержащего её.

Этот раздел содержит лишь вводную информацию по данной теме. Более подробное описание жизненного цикла активности и его функций обратного вызова см. в разделе «Жизненный цикл активности» .