Использование уведомлений Android

Эта кодовая лаборатория является частью курса Advanced Android in Kotlin. Вы получите максимальную отдачу от этого курса, если будете последовательно работать с лабораториями кода, но это не обязательно. Все кодовые лаборатории курса перечислены на целевой странице Advanced Android in Kotlin codelabs .

Введение

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

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

Уведомления могут доставлять своевременный материал, и они могут иметь кнопки, позволяющие пользователю выполнять быстрые действия, такие как отправка ответа или откладывание будильника. При нажатии на уведомление пользователь переходит к представлению в вашем приложении, связанному с содержимым уведомления.

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

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

Что вы уже должны знать

Вы должны быть знакомы с:

  • Как создавать приложения для Android на Kotlin. В частности, работа с Android SDK.
  • Как создавать приложения с помощью компонентов архитектуры и привязки данных.
  • Базовое понимание BroadcastReceivers
  • Базовое понимание AlarmManager

Что вы узнаете

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

Что ты будешь делать

  • Добавьте уведомление в стартовое приложение.
  • Отмените отправленное ранее уведомление.
  • Создавайте каналы для разных типов уведомлений.
  • Настройте уведомления в стартовом приложении.
  • Добавьте быстрые действия, чтобы сделать ваше уведомление интерактивным.
  • Отключите значки уведомлений.

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

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

В идеале таймер яйца должен использовать уведомления, чтобы сообщать пользователям, когда время истекло. Пользователь действительно должен знать, что яйца готовы немедленно, иначе яйца будут переварены! Уведомления являются визуальными, могут включать звуки и могут вызывать вибрацию устройства — все способы привлечь внимание пользователя! Так вы сможете добиться идеальных яиц и счастливых, сытых пользователей.

Чтобы получить пример приложения, вы можете:

Клонируйте репозиторий с GitHub и переключитесь на стартовую ветку.

$  git clone https://github.com/googlecodelabs/android-kotlin-notifications


Кроме того, вы можете загрузить репозиторий в виде Zip-файла, разархивировать его и открыть в Android Studio.

Скачать ZIP

  1. Откройте и запустите приложение в Android Studio.

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

  1. Проверьте исходный код. Стартовое приложение состоит из одного действия с именем MainActivity . Есть три подпакета с именами receiver , ui и util .

  • /receiver — пакет receiver содержит два широковещательных приемника с именами AlarmReceiver и SnoozeReceiver . AlarmReceiver запускается AlarmManager для отправки уведомления, когда истекает заданный пользователем таймер. SnoozeReceiver обрабатывает щелчок пользователя, чтобы отложить уведомление.
  • /ui — содержит EggTimerFragment , который является частью пользовательского интерфейса приложения. EggTimerViewModel отвечает за запуск и отмену таймера, а также за другие задачи приложения, связанные с жизненным циклом.
  • /util — В этом пакете два файла. BindingUtils.kt имеет адаптеры привязки для обеспечения привязки данных между пользовательским интерфейсом приложения и ViewModel . NotificationUtils.kt имеет методы расширения в NotificationManager .

Использование уведомлений — отличный способ привлечь внимание пользователей к вашему приложению. Независимо от того, запущено ли ваше приложение или запущено на переднем плане, уведомление будет отображаться в виде всплывающего окна в верхней части экрана и может включать звук или вибрацию. Чтобы создать уведомление, вам нужно использовать конструктор уведомлений и указать текст заголовка, текст содержимого и значок. Как только в конструкторе есть все необходимые поля, NotificationManager , который является системной службой, поможет вам отобразить это содержимое в виде уведомления. NotificationManager отвечает за отправку уведомления, обновление его содержимого и отмену уведомления. На следующих шагах вы добавите методы расширения в NotificationManager . Таким образом, каждый раз, когда вам нужно использовать NotificationManager , вы сможете использовать эти функции расширения для достижения необходимых вам функций.

Шаг 1. Создайте базовое уведомление

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

  1. Откройте класс NotificationUtils.kt и найдите TODO: Step 1.1 . Вы найдете совпадающие задачи в этой кодовой лаборатории и в коде приложения.
  2. Изучите данную sendNotification() . Вы будете расширять эту функцию расширения до NotificationManager для отправки уведомлений.
//NotificationUtils.kt
// TODO: Step 1.1 extension function to send messages (GIVEN)
/**
 * Builds and delivers a notification.
 *
 * @param messageBody, notification text.
 * @param context, activity context.
 */
fun NotificationManager.sendNotification(messageBody: String, applicationContext: Context) {
  1. Получите экземпляр построителя уведомлений, передайте контекст приложения и идентификатор канала. Идентификатор канала представляет собой строковое значение для канала.

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

//NotificationUtils.kt
// TODO: Step 1.2 get an instance of NotificationCompat.Builder
val builder = NotificationCompat.Builder(
        applicationContext,
        applicationContext.getString(R.string.egg_notification_channel_id)
)
  1. Установите значок уведомления, чтобы представлять ваше приложение, заголовок и текст содержимого для сообщения, которое вы хотите передать пользователю. Вы увидите дополнительные параметры для дальнейшей настройки уведомления в лаборатории кода, но это минимальный объем данных, который необходимо установить для отправки уведомления.
//NotificationUtils.kt
   // TODO: Step 1.3 set title, text and icon to builder
   .setSmallIcon(R.drawable.cooked_egg)
   .setContentTitle(applicationContext.getString(R.string.notification_title))
   .setContentText(messageBody)
  1. Затем вам нужно вызвать notify() с уникальным идентификатором для вашего уведомления и с объектом Notification из вашего компоновщика.

Этот идентификатор представляет текущий экземпляр уведомления и необходим для обновления или отмены этого уведомления. Поскольку ваше приложение будет иметь только одно активное уведомление в данный момент времени, вы можете использовать один и тот же идентификатор для всех своих уведомлений. Для этой цели вам уже предоставлена ​​константа с именем NOTIFICATION_ID в NotificationUtils.kt . Обратите внимание, что вы можете напрямую вызывать notify() , так как вы выполняете вызов из функции расширения в том же классе.

//NotificationUtils.kt
   // TODO: Step 1.4 call notify to send the notification
    // Deliver the notification
    notify(NOTIFICATION_ID, builder.build())
  1. Откройте ui/EggTimerViewModel.kt и найдите startTimer() . Эта функция создает сигнал тревоги с выбранным интервалом времени, когда пользователь включает таймер для яиц.
  2. Вы вызовете уведомление в этой функции, когда пользователь запустит таймер. Чтобы вызвать sendNotification() , которую вы реализовали ранее, вам нужен экземпляр NotificationManager . NotificationManager — это системная служба, предоставляющая все функции, доступные для API уведомлений, включая добавленную вами функцию расширения. В любое время, когда вы хотите отправить, отменить или обновить уведомление, вам необходимо запросить экземпляр NotificationManager из системы. Вызовите sendNotification()| функция с сообщением уведомления и с контекстом.
// EggTimerViewModel.kt
// TODO: Step 1.5 get an instance of NotificationManager 
// and call sendNotification

val notificationManager = ContextCompat.getSystemService(
    app, 
    NotificationManager::class.java
) as NotificationManager
                notificationManager.sendNotification(app.getString(R.string.timer_running), app)

Вы почти там. Однако, если вы запустите приложение сейчас и установите таймер, вы не получите уведомление.

  1. Откройте logcat и найдите "No Channel found" . Вы должны увидеть сообщение об ошибке, что egg_channel не существует. В следующих шагах вы узнаете больше о каналах уведомлений и исправите это.

Шаг 2: Каналы уведомлений

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

Каналы представляют собой «тип» уведомлений — например, ваш таймер для яиц может отправлять уведомления, когда яйцо приготовлено, а также использовать другой канал для отправки ежедневных уведомлений, чтобы напомнить вам, что нужно есть яйца на завтрак. Все уведомления в канале группируются вместе, и пользователи могут настраивать параметры уведомлений для всего канала. Это позволяет пользователям персонализировать свои настройки уведомлений в зависимости от интересующего их типа уведомлений. Например, ваши пользователи могут отключить уведомления о завтраке, но по-прежнему будут выбирать уведомления от таймера.

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

На шаге 1.1 вы использовали egg_notification_channel_id в качестве канала уведомлений, поэтому теперь вам нужно фактически создать и настроить параметры уведомлений и поведение этого канала.

  1. Откройте EggTimerFragment.kt и найдите createChannel() .
  2. Передайте уникальный идентификатор канала конструктору NotificationChannel .
  3. Передайте имя канала уведомлений, которое пользователи также увидят на экране настроек .
  4. В качестве последнего параметра передайте уровень важности для канала уведомлений. Уровни важности будут рассмотрены позже в этой кодовой лаборатории, поэтому сейчас вы можете использовать NotificationManag er.IMPORTANCE_LOW
  5. В notificationChannel установите для enableLights значение true. Этот параметр включит подсветку при отображении уведомления.
  6. В notificationChannel установите для lightColor значение red, чтобы отображать красный свет при отображении уведомления.
  7. В notificationChannel установите для enableVibration значение true, чтобы включить вибрацию.
  8. В notificationChannel установите описание канала на 'Time for breakf ».
  9. Получите экземпляр NotificationManager , вызвав getSystemService() .
  10. Вызовите createNotificationChannel() в NotificationManager и передайте notificationChannel , который вы создали на предыдущем шаге.
//EggTimerFragment.kt
private fun createChannel(channelId: String, channelName: String) {
    // TODO: Step 1.6 START create a channel
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val notificationChannel = NotificationChannel(
            channelId,
            channelName,
            // TODO: Step 2.4 change importance
            NotificationManager.IMPORTANCE_LOW
        )
        // TODO: Step 2.6 disable badges for this channel

        notificationChannel.enableLights(true)
        notificationChannel.lightColor = Color.RED
        notificationChannel.enableVibration(true)
        notificationChannel.description = "Time for breakfast"

        val notificationManager = requireActivity().getSystemService(
            NotificationManager::class.java
        )
        notificationManager.createNotificationChannel(notificationChannel)
    }
    // TODO: Step 1.6 END create channel
}
  1. Затем, чтобы создать канал, вам нужно вызвать createChannel() , которую вы только что написали (шаг 1.7). Эта функция принимает два параметра: идентификатор канала и имя канала. Вам нужно найти свой идентификатор канала и имя канала из строковых ресурсов, которые уже указаны в вашем проекте.
// EggTimerFragment.kt
    // TODO: Step 1.7 call createChannel
    createChannel(
          getString(R.string.egg_notification_channel_id),
          getString(R.string.egg_notification_channel_name)
    )
  1. Вам нужно передать идентификатор канала в конструктор уведомлений. Вы уже сделали это на шаге 1.2. Установка неправильного значения в качестве идентификатора канала приведет к сбою уведомления. Откройте NotificationUtils.kt , чтобы проверить правильность установленного ранее идентификатора канала.
// NotificationUtils.kt
val builder = NotificationCompat.Builder(
        applicationContext,
       // TODO: Step 1.8 verify the notification channel name
        applicationContext.getString(R.string.egg_notification_channel_id)
)
  1. Запустите приложение, и вы увидите, что приложение отправляет уведомление каждый раз, когда вы запускаете таймер.
  2. Потяните строку состояния и убедитесь, что заголовок, содержимое и значок уведомления такие же, как вы установили их на предыдущих шагах.
  3. Чтобы проверить только что созданный канал, закройте приложение и найдите значок приложения. Выполните долгое нажатие на значок приложения и выберите Информация о приложении .

  1. Выберите Уведомления из списка настроек. Вы должны увидеть новый канал с именем Egg прямо под настройкой « Показать уведомления ».

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

Шаг 3. Добавьте уведомления в свое приложение.

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

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

Ваше приложение использует AlarmManager для настройки будильника. Код, относящийся к AlarmManager , уже указан в начальном коде и используется для отображения всплывающего сообщения. AlarmManager отслеживает выбор желаемого времени и запускает функцию onReceive() AlarmReceiver.kt когда время истекло. Если вы откроете AlarmReceiver.kt и перейдете к onReceive() , вы должны увидеть всплывающее сообщение, которое отображается каждый раз, когда вы устанавливаете таймер для яиц.

  1. Откройте AlarmReceiver.kt , экземпляр NotificationManager , и вызовите sendNotification() с текстом сообщения и параметрами контекста.
// AlarmReceiver.kt
   // TODO: Step 1.9 add call to sendNotification
   val notificationManager = ContextCompat.getSystemService(
       context, 
       NotificationManager::class.java
   ) as NotificationManager
             
   notificationManager.sendNotification(
       context.getText(R.string.eggs_ready).toString(), 
       context
   )
  1. При желании удалите всплывающее уведомление, так как ваше приложение будет отправлять уведомление, когда таймер истекает.
// AlarmReceiver.kt
     // TODO: Step 1.10 [Optional] remove toast
//   Toast.makeText(
//       context, 
//       context.getText(R.string.eggs_ready),
//       Toast.LENGTH_SHORT
//   ).show()
  1. Запустите свое приложение. Вы должны видеть уведомление каждый раз, когда вы запускаете таймер и каждый раз, когда таймер истекает.

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

  1. Откройте EggTimerFragment.kt и удалите код уведомления для шага 1.5.
// EggTimeViewModel.kt

// TODO: Step 1.5 get an instance of NotificationManager 
// and call sendNotification
// val notificationManager = ContextCompat.getSystemService(
//      app,
//      NotificationManager::class.java
// ) as NotificationManager
// notificationManager.sendNotification(app.getString(R.string.eggs_ready), app)
  1. Запустите приложение еще раз.
  2. Установите таймер, поставьте его на задний план и дождитесь окончания времени. Вы увидите уведомление. Это гораздо более полезное уведомление.

Шаг 4. Добавьте намерение контента

  1. Запустите приложение еще раз, если оно еще не запущено.
  2. Щелкните уведомление. Ничего не произошло!

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

Intent — это объект обмена сообщениями, который вы можете использовать для запроса действия из другого компонента приложения. Намерения можно использовать для запуска действия, службы или доставки широковещательной рассылки. В этом случае вы используете это намерение, чтобы указать системе открывать MainActivity когда пользователь касается уведомления. Поскольку ваше приложение состоит только из одного представления, здесь у вас не так много вариантов. Тем не менее, в более крупном приложении уведомление должно создавать бесшовный интерфейс, выводя пользователя на экран, что имеет смысл, когда он взаимодействует с уведомлением.

  1. Откройте NotificationUtils.kt и найдите функцию расширения sendNotification() .
  2. Создайте Intent с вашим applicationContext и активностью, которую нужно запустить, MainActivity::class.java .
// NotificationUtils.kt

fun NotificationManager.sendNotification(messageBody: String, applicationContext: Context) {
    // Create the content intent for the notification, which launches
    // this activity
   // TODO: Step 1.11 create intent
    val contentIntent = Intent(applicationContext, MainActivity::class.java)

Вы создали намерение, но уведомление отображается за пределами вашего приложения. Чтобы намерение работало за пределами вашего приложения, вам нужно создать новый PendingIntent .

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

  1. Создайте PendingIntent с applicationContext , NOTIFICATION_ID , contentIntent , созданным на предыдущем шаге, и флагом PendingIntent . Флаг PendingIntent указывает возможность создания нового PendingIntent или использования существующего. Вам нужно установить PendingIntent.FLAG_UPDATE_CURRENT в качестве флага, так как вы не хотите создавать новое уведомление, если оно уже существует. Таким образом, вы будете изменять текущий PendingIntent , который связан с намерением, которое вы предоставляете.
// NotificationUtils.kt
   // TODO: Step 1.12 create PendingIntent
    val contentPendingIntent = PendingIntent.getActivity(
        applicationContext, 
        NOTIFICATION_ID,
        contentIntent,
        PendingIntent.FLAG_UPDATE_CURRENT
    )
  1. Передайте PendingIntent своему уведомлению. Вы делаете это, вызывая setContentIntent() в NotificationBuilder . Теперь, когда вы нажимаете на уведомление, PendingIntent будет запущен, открывая ваш MainActivity .
  2. Также задайте setAutoCancel() значение true , чтобы, когда пользователь нажимает на уведомление, уведомление само закрывалось, когда оно перенаправляло их в приложение.
// NotificationUtils.kt
    // TODO: Step 1.13 set content intent
    .setContentIntent(contentPendingIntent)
    .setAutoCancel(true)
  1. Запустите приложение еще раз.
  2. Установите таймер, переведите приложение в фоновый режим и дождитесь появления уведомления.
  3. Как только вы увидите уведомление, нажмите на уведомление, потянув строку состояния вниз, и посмотрите, как приложение выводится на передний план.

Шаг 5. Отмените уведомление

У вас есть функциональный таймер яйца с уведомлениями, но есть небольшая проблема. Если вы установите таймер, получите уведомление и снова установите таймер, предыдущее уведомление останется в строке состояния, пока работает новый таймер. Это может сбить пользователя с толку, если приложение работает в фоновом режиме, и может привести к недоваренным яйцам.

Чтобы это исправить, вам нужно очистить предыдущее уведомление при запуске нового таймера. Начните с создания еще одной функции расширения в вашем NotificationUtils.kt . NotificationManager имеет API для отмены всех активных уведомлений, который называется cancelAll () .

  1. Откройте NotificationsUtil.kt .
  2. Добавьте функцию расширения в NotificationManager , которая вызывает cancelAll() .
// NotificationUtils.kt

// TODO: Step 1.14 Cancel all notifications
/**
 * Cancels all notifications.
 *
 */
fun NotificationManager.cancelNotifications() {
    cancelAll()
}
  1. Откройте EggTimerViewModel.kt и перейдите к функции startTimer() .
  2. Внутри startTimer() получите экземпляр NotificationManager из системы и вызовите cancelNotifications() .
//  EggTimerViewModel.kt
   //TODO Step 1.15 call cancel notification
    val notificationManager =
       ContextCompat.getSystemService(
            app,
            NotificationManager::class.java
        ) as NotificationManager
    notificationManager.cancelNotifications()       
  1. Запустите приложение и запустите таймер.
  2. После того, как вы увидите уведомление, снова запустите таймер и наблюдайте, как наше приложение автоматически удаляет предыдущее уведомление из строки состояния.

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

Шаг 1. Стиль вашего уведомления

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

NotificationCompat предлагает встроенные стили для:

  • BigTextStyle , который может отображать большой блок текста, например отображать содержимое электронного письма в развернутом виде.
  • BigPictureStyle , который показывает крупноформатные уведомления, содержащие большое вложение изображения.
  • InboxStyle , который показывает текстовое содержимое в стиле беседы.
  • MediaStyle , который показывает элементы управления для воспроизведения мультимедиа.
  • MessagingStyle , который показывает крупноформатные уведомления, включающие несколько сообщений между любым количеством людей.

Вы можете найти больше информации о других стилях в документации по Create an Expandable Notification . На этом шаге вы будете использовать NotificationCompat.BigPictureStyle для создания расширяемого уведомления, которое показывает большое изображение яйца при раскрытии.

  1. Откройте NotificationUtils.kt и найдите sendNotification() .
  2. Начните с загрузки изображения из resources с помощью BitmapFactory .
// NotificationUtils.kt

// TODO: Step 2.0 add style
val eggImage = BitmapFactory.decodeResource(
     applicationContext.resources, 
     R.drawable.cooked_egg
)
  1. Создайте новый BigPictureStyle и установите свое изображение.
  2. Установите для bigLargeIcon() значение null , чтобы большой значок исчезал при раскрытии уведомления.
// NotificationUtils.kt

// TODO: Step 2.0 add style
val eggImage = BitmapFactory.decodeResource(
     applicationContext.resources, 
     R.drawable.cooked_egg
)
val bigPicStyle = NotificationCompat.BigPictureStyle()
        .bigPicture(eggImage)
        .bigLargeIcon(null)
  1. Установите стиль с помощью setStyle() на bigPicStyle .
  2. Установите большой значок с помощью setLargeIcon() на eggImage , чтобы изображение отображалось как меньший значок, когда уведомление свернуто.
// NotificationUtils.kt
// TODO: Step 2.1 add style to builder
.setStyle(bigPicStyle)
.setLargeIcon(eggImage)
  1. Запустите приложение и установите таймер. Когда уведомление отображается впервые, оно находится в свернутом состоянии в панели уведомлений. Если вы развернете уведомление, в расширенной области уведомлений отобразится большое изображение.

Шаг 2. Действия по уведомлению

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

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

Чтобы добавить кнопку действия, передайте PendingIntent в addAction() функция на застройщике. Это похоже на настройку действия касания уведомления по умолчанию с помощью вызова setContentIntent() , за исключением того, что вместо запуска действия вы можете делать множество других вещей, например, запустить BroadcastReceiver , который выполняет задание в фоновом режиме, чтобы действие выполнялось. не прерывать приложение, которое уже открыто.

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

  1. Откройте SnoozeReceiver.kt . Этот класс аналогичен классу AlarmReceiver , который вы использовали ранее. На следующих шагах вы добавите код, который вызовет onReceive() объекта SnoozeReceiver . Короче говоря, код в SnoozeReceiver создаст новый будильник для отправки нового уведомления через минуту. Прокрутите вниз функцию onReceive, получите экземпляр notificationManager из системы и вызовите cancelAll.
// SnoozeReceiver.kt
        val notificationManager = ContextCompat.getSystemService(
            context,
            NotificationManager::class.java
        ) as NotificationManager
        notificationManager.cancelAll()
  1. Чтобы использовать SnoozeReceiver , откройте NotificationUtils.kt .
  2. Создайте новый Intent snoozeIntent для SnoozeReceiver сразу после стиля в функции sendNotification() .
  3. Создайте ожидающее намерение, вызвав метод getBroadcast() для PendingIntent , который ожидает параметры в следующих шагах. Это PendingIntent будет использоваться системой для настройки нового будильника для публикации нового уведомления через 60 секунд, когда пользователь нажимает кнопку повтора.
  4. Первый параметр — это контекст приложения, в котором этот PendingIntent должен запускать действие.
  5. Второй параметр — это код запроса, который является кодом запроса для этого ожидающего намерения. Если вам нужно обновить или отменить это ожидающее намерение, вам нужно использовать этот код для доступа к ожидающему намерению.
  6. Затем добавьте объект snoozeIntent , который является целью запускаемой активности.
  7. Наконец, добавьте значение флага #FLAG_ONE_SHOT поскольку намерение будет использовано только один раз. Быстрое действие и уведомление исчезнут после первого нажатия, поэтому намерение можно использовать только один раз.
// NotificationUtils.kt

// TODO: Step 2.2 add snooze action
val snoozeIntent = Intent(applicationContext, SnoozeReceiver::class.java)
val snoozePendingIntent: PendingIntent = PendingIntent.getBroadcast(
    applicationContext, 
    REQUEST_CODE, 
    snoozeIntent, 
    FLAGS
)
  1. Затем вызовите addAction() для notificationBuilder . Эта функция ожидает, что иконка и текст описывают ваше действие для пользователя. Вам также необходимо добавить snoozeIntent . Это намерение будет использоваться для запуска правильного boadcastReceiver при нажатии на ваше действие.
// NotificationUtils.kt
// TODO: Step 2.3 add snooze action
.addAction(
    R.drawable.egg_icon, 
    applicationContext.getString(R.string.snooze),
    snoozePendingIntent
)
  1. Запустите приложение таймера яйца, чтобы проверить действие повтора.
  2. Запустите таймер и установите приложение в фоновом режиме. Как только таймер истечет, разверните уведомление, и вы увидите, что в уведомлении теперь есть кнопка повтора, которая откладывает таймер яйца еще на минуту.

Шаг 3. Важность уведомлений

Важность определяет, насколько уведомление должно визуально и звуково прерывать пользователя. Уведомления с более высокой важностью будут больше мешать пользователям.

Вы должны указать уровень важности в конструкторе NotificationChannel . Изначально вы установили низкую важность для приложения таймера яиц. Вы можете использовать один из пяти уровней важности: от IMPORTANCE_NONE(0) до IMPORTANCE_HIGH(4) . Уровень важности, который вы назначаете каналу, применяется ко всем сообщениям уведомлений, которые вы публикуете в нем.

Уровни важности канала

Видимый пользователем уровень важности

Важность (Android 8.0 и выше)

Приоритет (Android 7.1 и ниже)

Издает звук и появляется в виде хедз-ап уведомления (всплывает вверху экрана)

ВАЖНО_HIGH

PRIORITY_HIGH / PRIORITY_MAX

Издает звук

ВАЖНО_ПО УМОЛЧАНИЮ

PRIORITY_DEFAULT

Без звука

ВАЖНО_LOW

ПРИОРИТЕТ_НИЗКИЙ

Нет звука и не отображается в строке состояния

ВАЖНО_MIN

PRIORITY_MIN

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

Когда вы впервые создали уведомление на шаге 1.6, таймер яйца был настроен на отправку уведомлений с низким приоритетом, поскольку он был разработан, чтобы не беспокоить пользователя уведомлениями. Тем не менее, может быть хорошей идеей привлечь внимание пользователя до того, как яйцо пережарится. Чтобы изменить уровень важности уведомления, начните с настроек канала. Важность канала влияет на уровень прерывания всех уведомлений, публикуемых в канале, и должна быть указана в конструкторе NotificationChannel .

  1. Чтобы изменить уровень важности канала уведомлений вашего приложения, откройте EggTimerFragment.kt и перейдите к createChannel() . Измените уровень важности с IMPORTANCE_LOW на IMPORTANCE_HIGH .
// EggTimerFragment.kt
    val notificationChannel = NotificationChannel(
        channelId,
        channelName,
        // TODO: Step 2.4 change importance
        NotificationManager.IMPORTANCE_HIGH
    )

Для поддержки устройств под управлением Android 7.1 (уровень API 25) или ниже необходимо также вызывать setPriority() для каждого уведомления, используя константу приоритета из класса NotificationCompat .

  1. Откройте NotificationUtils.kt и добавьте следующее в объект построителя уведомлений.
// NotificationUtils.kt
   .addAction(
       R.drawable.common_google_signin_btn_icon_dark,
       applicationContext.getString(R.string.snooze),
       snoozePendingIntent
    )
   // TODO: Step 2.5 set priority
    .setPriority(NotificationCompat.PRIORITY_HIGH)
  1. Перед запуском приложения нажмите и удерживайте значок приложения на своем устройстве или эмуляторе и выберите «Удалить», чтобы очистить предыдущие настройки канала. Если вам не удастся удалить приложение, настройки приоритета канала не изменятся, и это не приведет к изменению поведения при публикации уведомления.
  2. Теперь снова запустите приложение и запустите таймер. На этот раз, когда уведомление будет доставлено, вы должны увидеть всплывающее окно в верхней части экрана, независимо от того, работает ли ваше приложение на переднем плане или в фоновом режиме.

Шаг 4. Значки уведомлений

Значки уведомлений — это маленькие точки, которые появляются на значке запуска связанного приложения, когда приложение имеет активное уведомление. Пользователи могут долго нажимать на значок приложения, чтобы открыть уведомления.

Эти точки, называемые значками, отображаются по умолчанию, и вашему приложению ничего не нужно делать. Однако могут быть ситуации, когда значки не имеют смысла для ваших уведомлений, поэтому вы можете отключить их для каждого канала, вызвав setShowBadge(false) для вашего объекта NotificationChannel . Поскольку таймер для яиц имеет только одно активное уведомление в данный момент времени, значок на значке вашего приложения не дает пользователям особых преимуществ. В следующих шагах вы отключите значок и будете показывать уведомление только для таймера яйца.

  1. Добавьте setShowBadge(false) в код создания канала для таймера яйца, чтобы отключить значки.
// EggTimerFragment.kt

    ).apply {
        // TODO: Step 2.6 disable badges for this channel
        setShowBadge(false)
    }
  1. Запустите приложение еще раз, запустите таймер и посмотрите на значок приложения. Вы не должны видеть никаких значков на значке приложения.

Код решения находится в основной ветке вашего загруженного кода .

  • Используйте класс NotificationManager для создания, отправки, обновления и отмены уведомления с помощью.
  • Используйте объект NotificationChannel с методом createNotificationChannel , чтобы задать канал для уведомления.
  • Используйте addAction() для добавления быстрых действий к уведомлению.
  • Используйте setShowBadge() для включения или отключения значков.
  • Стилизуйте свои уведомления, используя стили, которые унаследованы от Notification.Style.
  • Установите уровень важности с помощью NotificationChannel.setImportance()

Удасити курс:

Документация для разработчиков Android:

Ссылки на другие лаборатории кода в этом курсе см. на целевой странице Advanced Android in Kotlin codelabs.