Android-Benachrichtigungen verwenden

Dieses Codelab ist Teil des Kurses „Advanced Android in Kotlin“. Sie können den größten Nutzen aus diesem Kurs ziehen, wenn Sie die Codelabs der Reihe nach durcharbeiten. Das ist jedoch nicht zwingend erforderlich. Alle Codelabs des Kurses sind auf der Landingpage für Codelabs zu „Android für Fortgeschrittene mit Kotlin“ aufgeführt.

Einführung

Benachrichtigungen sind Nachrichten, die dem Nutzer außerhalb der Benutzeroberfläche Ihrer App angezeigt werden. Benachrichtigungen werden oben auf dem Display angezeigt, wenn das Gerät entsperrt ist. Je nach Sicherheitseinstellungen werden sie auch auf dem Sperrbildschirm angezeigt, wenn das Gerät gesperrt ist.

Eine typische Benachrichtigung besteht aus einem Titel, einer Beschreibung und einem Symbol. Eine Benachrichtigung kann auch anklickbare Aktionen, eine Schnellantwort, erweiterbare Inhalte und Bilder enthalten.

Benachrichtigungen können zeitnah Informationen liefern und Schaltflächen enthalten, über die Nutzer Schnellaktionen ausführen können, z. B. eine Antwort senden oder einen Wecker zurückstellen. Wenn ein Nutzer auf eine Benachrichtigung klickt, wird er zu einer Ansicht in Ihrer App weitergeleitet, die sich auf den Inhalt der Benachrichtigung bezieht.

Benachrichtigungen sind eine gute Möglichkeit, Nutzer an eine wichtige Aufgabe zu erinnern, sie über ein Ereignis zu informieren oder ihnen wichtige Informationen mitzuteilen, die sie sofort benötigen, während Ihre App im Hintergrund ausgeführt wird. Verwenden Sie Benachrichtigungen sparsam. Das ist nicht nur respektvoll gegenüber den Nutzern, sondern erhöht auch die Wahrscheinlichkeit, dass die Benachrichtigung Ihrer App die Aufmerksamkeit erhält, die sie verdient.

In diesem Codelab erfahren Sie, wie Sie Benachrichtigungen in einer Android-App erstellen und verwenden.

Was Sie bereits wissen sollten

Sie sollten mit Folgendem vertraut sein:

  • Android-Apps in Kotlin erstellen Insbesondere mit dem Android SDK.
  • Apps mit Architekturkomponenten und Datenbindung entwickeln
  • Grundlegendes Verständnis von BroadcastReceivers
  • Grundlegendes Verständnis von AlarmManager

Lerninhalte

  • So erstellen, gestalten und senden Sie eine Benachrichtigung.
  • Benachrichtigungen deaktivieren
  • Benachrichtigungskanäle erstellen
  • So fügen Sie Benachrichtigungen Schnellaktionen hinzu.
  • So werden Benachrichtigungsbadges auf dem App-Symbol angezeigt.

Aufgaben

  • Fügen Sie der Starter-App eine Benachrichtigung hinzu.
  • Die zuvor gesendete Benachrichtigung abbrechen.
  • Kanäle für verschiedene Arten von Benachrichtigungen erstellen
  • Passen Sie die Benachrichtigungen in der Starter-App an.
  • Fügen Sie Schnellaktionen hinzu, um Ihre Benachrichtigung interaktiv zu gestalten.
  • Deaktivieren Sie Benachrichtigungskennzeichen.

Eier zu kochen ist einfach, kann aber schwierig werden, wenn Sie die Zeit nicht im Blick behalten. In diesem Codelab arbeiten Sie an einer Eieruhr-App und machen sie perfekt – genau wie Ihre zukünftigen Eier. Sie beginnen mit einer funktionierenden Eieruhr-App, mit der der Nutzer verschiedene Garzeit-Einstellungen für verschiedene Eierarten festlegen kann. Der Timer zählt das ausgewählte Zeitintervall herunter und zeigt eine Benachrichtigung an, wenn die Eier fertig sind.

Das mag zwar funktionieren, ist aber alles andere als perfekt und nicht wirklich nutzerfreundlich. Die Benachrichtigung wird nur kurz angezeigt und kann daher leicht übersehen werden. Wenn die App nicht im Vordergrund ist oder das Gerät gesperrt ist, gibt es nach dem Verschwinden der Benachrichtigung keine visuelle Anzeige für den Status des Timers.

Idealerweise sollte der Eieruhr-Skill Benachrichtigungen verwenden, um Nutzer darüber zu informieren, wenn die Zeit abgelaufen ist. Der Nutzer muss wirklich wissen, dass die Eier sofort fertig sind, da sie sonst zu lange gekocht werden. Benachrichtigungen sind visuell, können Töne enthalten und das Gerät kann vibrieren – alles Möglichkeiten, die Aufmerksamkeit des Nutzers zu erregen. So können Sie perfekte Eier zubereiten und zufriedene, gut genährte Nutzer erreichen.

Sie haben folgende Möglichkeiten, die Beispiel-App zu erhalten:

Klonen Sie das Repository von GitHub und wechseln Sie zum Zweig starter.

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


Alternativ können Sie das Repository als ZIP-Datei herunterladen, entzippen und in Android Studio öffnen.

Zip herunterladen

  1. Öffnen Sie die App in Android Studio und führen Sie sie aus.

Sie sehen ein Bild eines Eis und ein Drop-down-Menü mit einer Liste vordefinierter Zeitintervalle zum Kochen eines Eis. Klicken Sie auf das Dreieck für das Drop-down-Menü Weichgekocht. Die erste Option in der Liste dient zu Testzwecken und stellt den Alarm auf nur 10 Sekunden ein. Neben der Liste befindet sich ein Schalter, mit dem der Eieruhr-Timer gestartet wird. Mit diesem Schalter können Sie den Eieruhr-Timer jederzeit starten und stoppen. Der Startercode ist voll funktionsfähig. Sie können also den Eieruhr-Timer einstellen und beobachten, wie er bis auf 0 herunterzählt. Wenn der Timer abgelaufen ist, wird eine Benachrichtigung wie unten dargestellt angezeigt.

  1. Quellcode prüfen Die Starter-App besteht aus einer einzelnen Aktivität mit dem Namen MainActivity. Es gibt drei Unterpakete mit den Namen receiver, ui und util.

  • /receiver: Das receiver-Paket enthält zwei Broadcast-Empfänger mit den Namen AlarmReceiver und SnoozeReceiver. AlarmReceiver wird von AlarmManager ausgelöst, um die Benachrichtigung zu senden, wenn der benutzerdefinierte Timer abgelaufen ist. SnoozeReceiver verarbeitet den Nutzerklick zum Schlummern der Benachrichtigung.
  • /ui: Dieses Verzeichnis enthält EggTimerFragment, das Teil der Benutzeroberfläche der App ist. EggTimerViewModel ist für das Starten und Abbrechen des Timers sowie für andere App-Aufgaben im Zusammenhang mit dem Lebenszyklus verantwortlich.
  • /util: Dieses Paket enthält zwei Dateien. BindingUtils.kt hat Bindungsadapter, um die Datenbindung zwischen der App-Benutzeroberfläche und ViewModel zu ermöglichen. NotificationUtils.kt hat Erweiterungsmethoden für NotificationManager.

Benachrichtigungen sind eine gute Möglichkeit, die Aufmerksamkeit der Nutzer auf Ihre App zu lenken. Unabhängig davon, ob Ihre App nicht ausgeführt wird oder im Vordergrund ausgeführt wird, wird durch eine Benachrichtigung ein Pop-up-Fenster oben auf dem Bildschirm angezeigt, das möglicherweise einen Ton oder eine Vibration enthält. Zum Erstellen einer Benachrichtigung benötigen Sie einen Benachrichtigungs-Builder sowie einen Titeltext, einen Inhaltstext und ein Symbol. Sobald der Builder alle erforderlichen Felder enthält, hilft Ihnen NotificationManager, ein Systemdienst, dabei, diesen Inhalt als Benachrichtigung anzuzeigen. NotificationManager ist für das Senden einer Benachrichtigung, das Aktualisieren des Inhalts und das Abbrechen der Benachrichtigung verantwortlich. In den folgenden Schritten fügen Sie NotificationManager Erweiterungsmethoden hinzu. So können Sie jedes Mal, wenn Sie NotificationManager verwenden müssen, diese Erweiterungsfunktionen nutzen, um die benötigte Funktionalität zu erhalten.

Schritt 1: Einfache Benachrichtigung erstellen

In dieser Aufgabe erstellen Sie eine neue Benachrichtigung, legen eine Nachricht für den Nutzer fest und senden die Benachrichtigung.

  1. Öffnen Sie den Kurs NotificationUtils.kt und suchen Sie nach TODO: Step 1.1. In diesem Codelab und im App-Code finden Sie entsprechende TODOs.
  2. Sehen Sie sich die angegebene Funktion sendNotification() an. Sie erweitern diese Erweiterungsfunktion auf NotificationManager, um Benachrichtigungen zu senden.
//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. Rufen Sie eine Instanz des Benachrichtigungs-Builders ab, übergeben Sie den App-Kontext und eine Channel-ID. Die Channel-ID ist ein Stringwert für den Channel.

Mit Benachrichtigungskanälen können Sie Benachrichtigungen gruppieren. Durch das Gruppieren ähnlicher Benachrichtigungstypen können Entwickler und Nutzer alle Benachrichtigungen im Channel steuern. Nachdem ein Kanal erstellt wurde, kann er zum Senden einer beliebigen Anzahl von Benachrichtigungen verwendet werden.

//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. Legen Sie das Benachrichtigungssymbol für Ihre App, einen Titel und den Inhaltstext für die Nachricht fest, die Sie dem Nutzer senden möchten. Im Codelab finden Sie weitere Optionen zum Anpassen Ihrer Benachrichtigung. Dies ist jedoch die Mindestmenge an Daten, die Sie festlegen müssen, um eine Benachrichtigung zu senden.
//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. Als Nächstes müssen Sie notify() mit einer eindeutigen ID für Ihre Benachrichtigung und mit dem Notification-Objekt aus Ihrem Builder aufrufen.

Diese ID steht für die aktuelle Benachrichtigungsinstanz und ist erforderlich, um diese Benachrichtigung zu aktualisieren oder abzubrechen. Da Ihre App zu einem bestimmten Zeitpunkt nur eine aktive Benachrichtigung hat, können Sie für alle Benachrichtigungen dieselbe ID verwenden. Dazu gibt es bereits eine Konstante mit dem Namen NOTIFICATION_ID in NotificationUtils.kt. Beachten Sie, dass Sie notify() direkt aufrufen können, da der Aufruf aus einer Erweiterungsfunktion in derselben Klasse erfolgt.

//NotificationUtils.kt
   // TODO: Step 1.4 call notify to send the notification
    // Deliver the notification
    notify(NOTIFICATION_ID, builder.build())
  1. Öffnen Sie ui/EggTimerViewModel.kt und suchen Sie nach der Funktion startTimer(). Mit dieser Funktion wird ein Alarm mit dem ausgewählten Zeitintervall erstellt, wenn der Nutzer den Eieruhr-Timer aktiviert.
  2. In dieser Funktion lösen Sie eine Benachrichtigung aus, wenn der Nutzer den Timer startet. Um die zuvor implementierte Funktion sendNotification() aufzurufen, benötigen Sie eine Instanz von NotificationManager. NotificationManager ist ein Systemdienst, der alle für die Notifications API bereitgestellten Funktionen bereitstellt, einschließlich der von Ihnen hinzugefügten Erweiterungsfunktion. Wenn Sie eine Benachrichtigung senden, abbrechen oder aktualisieren möchten, müssen Sie eine Instanz von NotificationManager vom System anfordern. Rufen Sie die Funktion sendNotification()| mit der Benachrichtigungsnachricht und dem Kontext auf.
// 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)

Fast geschafft. Wenn Sie Ihre App jetzt ausführen und den Timer einstellen, erhalten Sie jedoch keine Benachrichtigung.

  1. Öffnen Sie logcat und suchen Sie nach "No Channel found". Es sollte eine Fehlermeldung angezeigt werden, dass egg_channel nicht vorhanden ist. In den folgenden Schritten erfahren Sie mehr über Benachrichtigungskanäle und wie Sie das Problem beheben können.

Schritt 2: Benachrichtigungskanäle

Ab API-Ebene 26 müssen alle Benachrichtigungen einem Kanal zugewiesen werden. Wenn Sie das App-Launcher-Symbol gedrückt halten, „App-Info“ und dann „Benachrichtigungen“ auswählen, wird eine Liste der Benachrichtigungskanäle angezeigt, die mit der App verknüpft sind. Derzeit ist die Liste leer, da für Ihre App noch keine Kanäle erstellt wurden.

Kanäle stellen einen „Typ“ von Benachrichtigung dar. Ihr Eierkocher kann beispielsweise eine Benachrichtigung senden, wenn das Ei fertig gekocht ist, und über einen anderen Kanal tägliche Benachrichtigungen senden, um Sie daran zu erinnern, dass Sie zum Frühstück Eier essen sollen. Alle Benachrichtigungen in einem Channel werden gruppiert und Nutzer können die Benachrichtigungseinstellungen für einen ganzen Channel konfigurieren. So können Nutzer ihre Benachrichtigungseinstellungen an die Art der Benachrichtigung anpassen, die sie erhalten möchten. Nutzer können beispielsweise die Benachrichtigungen zum Frühstück deaktivieren, aber weiterhin Benachrichtigungen vom Timer erhalten.

Entwickler legen die anfänglichen Einstellungen, die Wichtigkeit und das Verhalten fest, die auf alle Benachrichtigungen in einem Kanal angewendet werden sollen. Nachdem Sie die anfänglichen Einstellungen festgelegt haben, können Nutzer diese Einstellungen überschreiben.

In Schritt 1.1 haben Sie egg_notification_channel_id als Benachrichtigungskanal verwendet. Jetzt müssen Sie die Benachrichtigungseinstellungen und das Verhalten dieses Kanals erstellen und anpassen.

  1. Öffnen Sie EggTimerFragment.kt und suchen Sie nach der Funktion createChannel().
  2. Übergeben Sie die eindeutige Channel-ID an den Konstruktor von NotificationChannel.
  3. Übergeben Sie den Namen des Benachrichtigungschannels, den Nutzer auch auf dem Bildschirm Einstellungen sehen.
  4. Übergeben Sie als letzten Parameter den Wichtigkeitsgrad für den Benachrichtigungschannel. Wichtigkeitsstufen werden später in diesem Codelab behandelt. Verwenden Sie vorerst NotificationManager.IMPORTANCE_LOW.
  5. Legen Sie für das notificationChannel-Objekt enableLights auf „true“ fest. Mit dieser Einstellung werden die Lichter eingeschaltet, wenn eine Benachrichtigung angezeigt wird.
  6. Legen Sie für das notificationChannel-Objekt lightColor auf „red“ (rot) fest, damit bei einer Benachrichtigung ein rotes Licht angezeigt wird.
  7. Setzen Sie im notificationChannel-Objekt enableVibration auf „true“, um die Vibration zu aktivieren.
  8. Legen Sie für das notificationChannel-Objekt die Kanalbeschreibung auf ‘Time for breakfast' fest.
  9. Rufen Sie getSystemService() auf, um eine Instanz von NotificationManager zu erhalten.
  10. Rufen Sie createNotificationChannel() für NotificationManager auf und übergeben Sie das notificationChannel-Objekt, das Sie im vorherigen Schritt erstellt haben.
//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. Als Nächstes müssen Sie die gerade geschriebene Funktion createChannel() (Schritt 1.7) aufrufen, um einen Channel zu erstellen. Diese Funktion verwendet zwei Parameter: die Kanal-ID und den Kanalnamen. Sie müssen Ihre Kanal-ID und Ihren Kanalnamen aus den String-Ressourcen abrufen, die bereits in Ihrem Projekt vorhanden sind.
// EggTimerFragment.kt
    // TODO: Step 1.7 call createChannel
    createChannel(
          getString(R.string.egg_notification_channel_id),
          getString(R.string.egg_notification_channel_name)
    )
  1. Sie müssen die Kanal-ID an den Benachrichtigungs-Builder übergeben. Das haben Sie bereits in Schritt 1.2 erledigt. Wenn Sie einen falschen Wert als Channel-ID festlegen, schlägt die Benachrichtigung fehl. Öffnen Sie NotificationUtils.kt, um zu prüfen, ob die von Ihnen festgelegte Kanal-ID korrekt ist.
// 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. Führen Sie die App aus. Sie werden sehen, dass die App jedes Mal, wenn Sie den Timer starten, eine Benachrichtigung sendet.
  2. Ziehen Sie die Statusleiste nach unten und prüfen Sie, ob Titel, Inhalt und Symbol der Benachrichtigung den Einstellungen entsprechen, die Sie in den vorherigen Schritten vorgenommen haben.
  3. Schließe die App und suche nach dem App-Symbol, um den neu erstellten Kanal zu prüfen. Halten Sie das App-Symbol gedrückt und wählen Sie App-Info aus.

  1. Wählen Sie in der Liste der Einstellungen Benachrichtigungen aus. Unter der Einstellung Benachrichtigungen anzeigen sollte ein neuer Kanal mit dem Namen Egg angezeigt werden.

Wenn Sie die App ausführen, wird die Benachrichtigung jetzt angezeigt. Sowohl Sie als App-Entwickler als auch Ihre Nutzer können die Einstellungen und das Verhalten für alle Benachrichtigungen anpassen, die über diesen Kanal gesendet werden. Glückwunsch, Sie haben eine Benachrichtigung erstellt.

Schritt 3: Benachrichtigungen in Ihre App einfügen

Bisher wird nur die grundlegende Verwendung der Notifications API gezeigt. Es ist jedoch nicht sinnvoll, eine Benachrichtigung direkt nach dem Starten des Timers zu senden. Nutzer würden wahrscheinlich lieber benachrichtigt werden, wenn das Ei fertig ist. Im nächsten Teil des Codelabs beheben Sie dieses Problem und ändern die Toast-Nachricht in eine Benachrichtigung.

Sie haben die Benachrichtigung bereits gesendet und beobachtet, wie sie den Nutzern angezeigt wird. Das war jedoch nur der erste Schritt, um ansprechende Benachrichtigungen zu erstellen. In diesem Schritt ändern Sie den Zeitpunkt, zu dem die Benachrichtigung gesendet wird.

In Ihrer App wird AlarmManager verwendet, um einen Wecker zu stellen. Der Code für AlarmManager ist bereits im Startcode enthalten und wird zum Anzeigen der Toast-Meldung verwendet. AlarmManager behält die gewünschte Zeit im Blick und löst die onReceive()-Funktion von AlarmReceiver.kt aus, wenn die Zeit abgelaufen ist. Wenn Sie AlarmReceiver.kt öffnen und zu onReceive() navigieren, sollte die Kurzmitteilung angezeigt werden, die jedes Mal eingeblendet wird, wenn Sie einen Kurzzeitwecker einstellen.

  1. Öffnen Sie AlarmReceiver.kt, eine Instanz von NotificationManager, und rufen Sie die Funktion sendNotification() mit dem Nachrichtentext und den Kontextparametern auf.
// 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. Optional können Sie den Toast entfernen, da Ihre App eine Benachrichtigung sendet, wenn der Timer abgelaufen ist.
// AlarmReceiver.kt
     // TODO: Step 1.10 [Optional] remove toast
//   Toast.makeText(
//       context, 
//       context.getText(R.string.eggs_ready),
//       Toast.LENGTH_SHORT
//   ).show()
  1. Führen Sie Ihre App aus . Sie sollten jedes Mal, wenn Sie den Timer starten und wenn er abgelaufen ist, eine Benachrichtigung erhalten.

Das ist nicht ideal. Sie möchten nicht zu viele Benachrichtigungen an Ihre Nutzer senden. Sie können die erste Benachrichtigung entfernen, die gesendet wird, wenn der Nutzer den Timer startet.

  1. Öffnen Sie EggTimerFragment.kt und entfernen Sie den Benachrichtigungscode für Schritt 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. Führen Sie die App noch einmal aus.
  2. Stellen Sie einen Timer ein, minimieren Sie die App und warten Sie, bis die Zeit abgelaufen ist. Sie sehen eine Benachrichtigung. Das ist eine viel nützlichere Benachrichtigung.

Schritt 4: Inhaltsabsicht hinzufügen

  1. Führen Sie die App noch einmal aus, falls sie noch nicht ausgeführt wird.
  2. Klicken Sie auf die Benachrichtigung. Es passiert nichts!

Es ist gut, die Benachrichtigung anzuzeigen und den Nutzer zu informieren. Wenn ein Nutzer jedoch auf eine Benachrichtigung klickt, erwartet er, zur entsprechenden App zurückzukehren. In diesem Teil des Codelabs fügen Sie Ihrer Benachrichtigung einen Intent hinzu, um den Nutzer zum Timerbildschirm zurückzubringen.

Ein Intent ist ein Messaging-Objekt, mit dem Sie eine Aktion von einer anderen App-Komponente anfordern können. Intents können verwendet werden, um eine Aktivität oder einen Dienst zu starten oder eine Broadcast-Nachricht zu senden. In diesem Fall verwenden Sie diesen Intent, um dem System mitzuteilen, dass MainActivity geöffnet werden soll, wenn der Nutzer auf die Benachrichtigung tippt. Da Ihre App nur aus einer einzigen Ansicht besteht, haben Sie hier nicht viele Möglichkeiten. Bei einer größeren App sollte die Benachrichtigung jedoch für eine nahtlose Nutzererfahrung sorgen, indem der Nutzer zu einem Bildschirm weitergeleitet wird, der für die Interaktion mit der Benachrichtigung sinnvoll ist.

  1. Öffnen Sie NotificationUtils.kt und suchen Sie nach der Erweiterungsfunktion sendNotification().
  2. Erstellen Sie einen Intent mit Ihrem applicationContext und der zu startenden Aktivität 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)

Sie haben den Intent erstellt, die Benachrichtigung wird aber außerhalb Ihrer App angezeigt. Damit ein Intent außerhalb Ihrer App funktioniert, müssen Sie einen neuen PendingIntent erstellen.

PendingIntent gewährt einer anderen Anwendung oder dem System Rechte, um eine Aktion im Namen Ihrer Anwendung auszuführen. Eine PendingIntent ist lediglich ein Verweis auf ein vom System verwaltetes Token, das die Originaldaten beschreibt, die zum Abrufen verwendet wurden. Das bedeutet, dass das PendingIntent auch dann noch von anderen Prozessen verwendet werden kann, an die es übergeben wurde, wenn der Prozess der zugehörigen Anwendung beendet wird. In diesem Fall verwendet das System den ausstehenden Intent, um die App in Ihrem Namen zu öffnen, unabhängig davon, ob die Timer-App ausgeführt wird.

  1. Erstellen Sie ein PendingIntent mit applicationContext, NOTIFICATION_ID, dem contentIntent, das Sie im vorherigen Schritt erstellt haben, und dem Flag PendingIntent. Mit dem Flag PendingIntent wird angegeben, ob eine neue PendingIntent erstellt oder eine vorhandene verwendet werden soll. Sie müssen PendingIntent.FLAG_UPDATE_CURRENT als Flag festlegen, da Sie keine neue Benachrichtigung erstellen möchten, wenn bereits eine vorhanden ist. So ändern Sie den aktuellen PendingIntent, der mit dem von Ihnen angegebenen Intent verknüpft ist.
// NotificationUtils.kt
   // TODO: Step 1.12 create PendingIntent
    val contentPendingIntent = PendingIntent.getActivity(
        applicationContext, 
        NOTIFICATION_ID,
        contentIntent,
        PendingIntent.FLAG_UPDATE_CURRENT
    )
  1. Übergeben Sie die PendingIntent an Ihre Benachrichtigung. Rufen Sie dazu setContentIntent() für die NotificationBuilder auf. Wenn Sie jetzt auf die Benachrichtigung klicken, wird PendingIntent ausgelöst und MainActivity wird geöffnet.
  2. Setzen Sie setAutoCancel() außerdem auf true, damit die Benachrichtigung geschlossen wird, wenn der Nutzer darauf tippt und zur App weitergeleitet wird.
// NotificationUtils.kt
    // TODO: Step 1.13 set content intent
    .setContentIntent(contentPendingIntent)
    .setAutoCancel(true)
  1. Starten Sie die App noch einmal.
  2. Stellen Sie einen Timer ein, minimieren Sie die App und warten Sie, bis die Benachrichtigung angezeigt wird.
  3. Wenn Sie die Benachrichtigung sehen, klicken Sie darauf, indem Sie die Statusleiste nach unten ziehen, und beobachten Sie, wie die App in den Vordergrund geholt wird.

Schritt 5: Benachrichtigung abbrechen

Sie haben einen funktionierenden Eieruhr-Skill mit Benachrichtigungen, aber es gibt ein kleines Problem. Wenn Sie den Timer stellen, eine Benachrichtigung erhalten und den Timer noch einmal stellen, bleibt die vorherige Benachrichtigung in der Statusleiste, während der neue Timer läuft. Das kann Nutzer verwirren, wenn die App im Hintergrund ausgeführt wird, und zu nicht durchgegarten Eiern führen.

Um das Problem zu beheben, müssen Sie die vorherige Benachrichtigung löschen, wenn Sie einen neuen Timer starten. Erstellen Sie zuerst eine weitere Erweiterungsfunktion in Ihrem NotificationUtils.kt. NotificationManager bietet eine API zum Abbrechen aller aktiven Benachrichtigungen namens cancelAll().

  1. Öffnen Sie NotificationsUtil.kt.
  2. Fügen Sie NotificationManager eine Erweiterungsfunktion hinzu, die cancelAll() aufruft.
// NotificationUtils.kt

// TODO: Step 1.14 Cancel all notifications
/**
 * Cancels all notifications.
 *
 */
fun NotificationManager.cancelNotifications() {
    cancelAll()
}
  1. Öffnen Sie EggTimerViewModel.kt und rufen Sie die Funktion startTimer() auf.
  2. Rufen Sie in startTimer() eine Instanz von NotificationManager aus dem System ab und rufen Sie cancelNotifications() auf.
//  EggTimerViewModel.kt
   //TODO Step 1.15 call cancel notification
    val notificationManager =
       ContextCompat.getSystemService(
            app,
            NotificationManager::class.java
        ) as NotificationManager
    notificationManager.cancelNotifications()       
  1. Führen Sie die App aus und starten Sie den Timer.
  2. Nachdem Sie die Benachrichtigung gesehen haben, starten Sie den Timer noch einmal und beobachten Sie, wie unsere App die vorherige Benachrichtigung automatisch aus der Statusleiste löscht.

Das Benachrichtigungs-Framework bietet Entwicklern eine Vielzahl von Anpassungsoptionen, mit denen sie benutzerdefinierte Aktionen festlegen und ihre Benachrichtigungen nach Bedarf gestalten können. In dieser Aufgabe lernen Sie, wie Sie die Benachrichtigungen für den Eieruhr-Timer anpassen.

Schritt 1: Benachrichtigung gestalten

Wenn Sie das Design Ihrer Benachrichtigung an Ihre Anforderungen und den Benachrichtigungsinhalt anpassen, heben sich Ihre Benachrichtigungen ab und sehen eher wie eine Erweiterung Ihrer Anwendung aus. Das Benachrichtigungs-Framework bietet mehrere integrierte Stile, die Sie verwenden können. Sie können aber auch eigene Stile erstellen.

NotificationCompat bietet integrierte Stile für:

  • BigTextStyle, in dem ein großer Textblock angezeigt werden kann, z. B. der Inhalt einer E-Mail, wenn er maximiert wird.
  • BigPictureStyle, in dem großformatige Benachrichtigungen mit einem großen Bildanhang angezeigt werden.
  • InboxStyle, in dem Textinhalte im Konversationsstil angezeigt werden.
  • MediaStyle mit Steuerelementen für die Medienwiedergabe.
  • MessagingStyle: Hier werden großformatige Benachrichtigungen mit mehreren Nachrichten zwischen einer beliebigen Anzahl von Personen angezeigt.

Weitere Informationen zu anderen Stilen finden Sie in der Dokumentation unter Maximierbare Benachrichtigung erstellen. In diesem Schritt verwenden Sie NotificationCompat.BigPictureStyle, um eine maximierbare Benachrichtigung zu erstellen, die im maximierten Zustand ein großes Bild eines Eis zeigt.

  1. Öffnen Sie NotificationUtils.kt und suchen Sie nach der Funktion sendNotification().
  2. Laden Sie zuerst ein Bild aus resources mit dem BitmapFactory.
// NotificationUtils.kt

// TODO: Step 2.0 add style
val eggImage = BitmapFactory.decodeResource(
     applicationContext.resources, 
     R.drawable.cooked_egg
)
  1. Erstellen Sie ein neues BigPictureStyle und legen Sie Ihr Bild fest.
  2. Legen Sie für bigLargeIcon() den Wert null fest, damit das große Symbol verschwindet, wenn die Benachrichtigung maximiert wird.
// 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. Legen Sie den Stil mit setStyle() auf bigPicStyle fest.
  2. Legen Sie das große Symbol mit setLargeIcon() auf eggImage fest, damit das Bild als kleineres Symbol angezeigt wird, wenn die Benachrichtigung minimiert ist.
// NotificationUtils.kt
// TODO: Step 2.1 add style to builder
.setStyle(bigPicStyle)
.setLargeIcon(eggImage)
  1. Führen Sie die App aus und stellen Sie einen Timer ein. Wenn die Benachrichtigung zum ersten Mal angezeigt wird, ist sie in der Benachrichtigungsleiste minimiert. Wenn Sie die Benachrichtigung maximieren, wird im erweiterten Benachrichtigungsbereich ein großes Bild angezeigt.

Schritt 2: Benachrichtigungsaktionen

Benachrichtigungsaktionen sind eine weitere Anpassung, die Sie Ihren Benachrichtigungen hinzufügen können. Wenn Nutzer derzeit auf Ihre Benachrichtigungen klicken, werden sie zu Ihrer App weitergeleitet. Zusätzlich zu dieser Standardbenachrichtigungsaktion kannst du Aktionsschaltflächen hinzufügen, um dem Nutzer die Möglichkeit zu geben, eine auf die App bezogene Aufgabe über die Benachrichtigung auszuführen.

Eine Benachrichtigung kann bis zu drei Aktionsschaltflächen enthalten, über die der Nutzer schnell reagieren kann, z. B. eine Erinnerung zurückstellen oder auf eine SMS antworten. Diese Aktionsschaltflächen sollten die Aktion, die ausgeführt wird, wenn der Nutzer auf die Benachrichtigung tippt, nicht duplizieren.

Um eine Aktionsschaltfläche hinzuzufügen, übergeben Sie ein PendingIntent an die Funktion addAction() im Builder. Das ist ähnlich wie beim Einrichten der Standard-Tippaktion der Benachrichtigung durch Aufrufen von setContentIntent(). Anstatt eine Aktivität zu starten, können Sie jedoch verschiedene andere Aktionen ausführen, z. B. einen BroadcastReceiver starten, der einen Job im Hintergrund ausführt, damit die Aktion die bereits geöffnete App nicht unterbricht.

In diesem Codelab ist bereits ein BoadcastReceiver mit dem Namen SnoozeReceiver vorhanden. Mit SnoozeReceiver erhalten Sie den Nutzerklick auf die Benachrichtigungsaktion. In den folgenden Schritten fügen Sie Code hinzu, um die Eieruhr-Benachrichtigung für 60 Sekunden zu verschieben, wenn der Nutzer auf die Schaltfläche zum Verschieben klickt. Wenn auf die Schlummerfunktion geklickt wird, erhält die SnoozeReceiver einen Intent und erstellt einen neuen Wecker, um nach 60 Sekunden eine neue Benachrichtigung zu senden.

  1. Öffnen Sie SnoozeReceiver.kt. Diese Klasse ähnelt AlarmReceiver, die Sie bereits verwendet haben. In den folgenden Schritten fügen Sie Code hinzu, der die onReceive()-Funktion des SnoozeReceiver auslöst. Kurz gesagt: Der Code in SnoozeReceiver erstellt einen neuen Alarm, um eine Minute später eine neue Benachrichtigung zu senden. Scrolle in der Funktion „onReceive“ nach unten, rufe eine Instanz von „notificationManager“ vom System ab und rufe „cancelAll“ auf.
// SnoozeReceiver.kt
        val notificationManager = ContextCompat.getSystemService(
            context,
            NotificationManager::class.java
        ) as NotificationManager
        notificationManager.cancelAll()
  1. Wenn Sie SnoozeReceiver verwenden möchten, öffnen Sie NotificationUtils.kt.
  2. Erstellen Sie ein neues Intent snoozeIntent für das SnoozeReceiver direkt nach dem Stil in der Funktion sendNotification().
  3. Erstellen Sie einen ausstehenden Intent, indem Sie die Methode getBroadcast() für PendingIntent aufrufen. Dazu sind die Parameter in den folgenden Schritten erforderlich. Diese PendingIntent wird vom System verwendet, um einen neuen Wecker zu stellen, der 60 Sekunden nach dem Tippen auf die Schlummertaste eine neue Benachrichtigung sendet.
  4. Der erste Parameter ist der Anwendungskontext, in dem diese PendingIntent die Aktivität starten soll.
  5. Der zweite Parameter ist der Anfragecode für diesen ausstehenden Intent. Wenn Sie diesen ausstehenden Intent aktualisieren oder abbrechen möchten, müssen Sie mit diesem Code darauf zugreifen.
  6. Fügen Sie als Nächstes das snoozeIntent-Objekt hinzu. Das ist der Intent der zu startenden Aktivität.
  7. Fügen Sie zum Schluss den Flag-Wert #FLAG_ONE_SHOT hinzu, da die Intention nur einmal verwendet wird. Die Schnellaktion und die Benachrichtigung werden nach dem ersten Tippen nicht mehr angezeigt. Der Intent kann also nur einmal verwendet werden.
// 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. Rufen Sie als Nächstes die Funktion addAction() für notificationBuilder auf. Diese Funktion erwartet ein Symbol und einen Text, um die Aktion für den Nutzer zu beschreiben. Außerdem müssen Sie die snoozeIntent hinzufügen. Mit diesem Intent wird der richtige boadcastReceiver ausgelöst, wenn auf Ihre Aktion geklickt wird.
// NotificationUtils.kt
// TODO: Step 2.3 add snooze action
.addAction(
    R.drawable.egg_icon, 
    applicationContext.getString(R.string.snooze),
    snoozePendingIntent
)
  1. Führen Sie die Eieruhr-App aus, um die Schlummerfunktion zu testen.
  2. Starten Sie den Timer und minimieren Sie die App. Wenn der Timer abgelaufen ist, maximieren Sie die Benachrichtigung. Sie sehen nun, dass die Benachrichtigung eine Schaltfläche zum Schlummern hat, mit der der Eieruhr-Timer um eine weitere Minute verlängert wird.

Schritt 3: Wichtigkeit von Benachrichtigungen

Die Wichtigkeit bestimmt, in welchem Ausmaß der Nutzer durch die Benachrichtigung visuell und akustisch unterbrochen werden soll. Benachrichtigungen mit höherer Wichtigkeit unterbrechen Nutzer stärker.

Sie müssen die Wichtigkeitsstufe im NotificationChannel-Konstruktor angeben. Du hast ursprünglich eine niedrige Priorität für die Eieruhr-App festgelegt. Du kannst eine von fünf Prioritätsstufen verwenden, die von IMPORTANCE_NONE(0) bis IMPORTANCE_HIGH(4) reichen. Die Wichtigkeitsstufe, die Sie einem Channel zuweisen, gilt für alle Benachrichtigungen, die Sie dort posten.

Wichtigkeitsstufen für Channels

Für Nutzer sichtbare Prioritätsstufe

Wichtigkeit (Android 8.0 und höher)

Priorität (Android 7.1 und niedriger)

Akustisches Signal ertönt, Vorabbenachrichtigung wird angezeigt (oben auf dem Display)

IMPORTANCE_HIGH

PRIORITY_HIGH / PRIORITY_MAX

Akustisches Signal

IMPORTANCE_DEFAULT

PRIORITY_DEFAULT

Kein Ton

IMPORTANCE_LOW

PRIORITY_LOW

Kein Ton und wird nicht auf der Statusleiste angezeigt

IMPORTANCE_MIN

PRIORITY_MIN

Informationen zur Auswahl einer geeigneten Prioritätsstufe finden Sie im Designleitfaden für Benachrichtigungen unter „Prioritätsstufen“. Sie sollten die Wichtigkeit von Benachrichtigungen in Ihrer App sorgfältig auswählen. Die Wichtigkeit von Channels sollte so gewählt werden, dass die Zeit und Aufmerksamkeit der Nutzer berücksichtigt werden. Wenn eine unwichtige Benachrichtigung als dringend getarnt wird, kann dies zu unnötiger Aufregung führen und ablenken. Nutzer haben die volle Kontrolle über die Wichtigkeit ihrer Benachrichtigungen. Wenn Sie also eine störende Benachrichtigung erstellen, können sie Ihren Benachrichtigungskanal vollständig deaktivieren.

Als Sie die Benachrichtigung in Schritt 1.6 erstellt haben, wurde der Eieruhr-Timer so eingestellt, dass Benachrichtigungen mit niedriger Priorität gesendet werden, da der Nutzer nicht durch Benachrichtigungen gestört werden soll. Es ist jedoch ratsam, die Aufmerksamkeit des Nutzers zu erregen, bevor das Ei zu lange gekocht wird. Wenn Sie die Wichtigkeit der Benachrichtigung ändern möchten, beginnen Sie mit den Kanaleinstellungen. Die Kanalwichtigkeit wirkt sich auf die Unterbrechungsstufe aller Benachrichtigungen aus, die im Kanal gepostet werden. Sie muss im NotificationChannel-Konstruktor angegeben werden.

  1. Wenn Sie die Wichtigkeitsstufe des Benachrichtigungschannels Ihrer App ändern möchten, öffnen Sie EggTimerFragment.kt und rufen Sie createChannel() auf. Ändern Sie die Wichtigkeit von IMPORTANCE_LOW in IMPORTANCE_HIGH.
// EggTimerFragment.kt
    val notificationChannel = NotificationChannel(
        channelId,
        channelName,
        // TODO: Step 2.4 change importance
        NotificationManager.IMPORTANCE_HIGH
    )

Wenn Sie Geräte mit Android 7.1 (API-Ebene 25) oder niedriger unterstützen möchten, müssen Sie auch für jede Benachrichtigung setPriority() aufrufen und dabei eine Prioritätskonstante aus der Klasse NotificationCompat verwenden.

  1. Öffnen Sie NotificationUtils.kt und fügen Sie dem Notification Builder-Objekt Folgendes hinzu.
// 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. Bevor Sie die App ausführen, klicken Sie auf Ihrem Gerät oder Emulator lange auf das App-Symbol und wählen Sie „Deinstallieren“ aus, um vorherige Kanaleinstellungen zu löschen. Wenn Sie die App nicht deinstallieren, ändern sich die Einstellungen für die Kanalpriorität nicht und es kommt zu keiner Verhaltensänderung, wenn die Benachrichtigung gesendet wird.
  2. Führen Sie die App jetzt noch einmal aus und starten Sie den Timer. Wenn die Benachrichtigung zugestellt wird, sollte oben auf dem Bildschirm ein Pop-up-Fenster angezeigt werden, unabhängig davon, ob Ihre App im Vordergrund oder im Hintergrund ausgeführt wird.

Schritt 4: Benachrichtigungssymbole

Benachrichtigungskennzeichen sind kleine Punkte, die auf dem Launcher-Symbol der zugehörigen App angezeigt werden, wenn die App eine aktive Benachrichtigung hat. Nutzer können lange auf das App-Symbol drücken, um die Benachrichtigungen aufzurufen.

Diese Punkte, sogenannte Badges, werden standardmäßig angezeigt. Ihre App muss nichts weiter tun. Es kann jedoch Situationen geben, in denen Badges für Ihre Benachrichtigungen nicht sinnvoll sind. Sie können sie daher channelweise deaktivieren, indem Sie setShowBadge(false) für Ihr NotificationChannel-Objekt aufrufen. Da der Eieruhr-Timer jeweils nur eine aktive Benachrichtigung hat, bietet das Badge auf Ihrem App-Symbol für Ihre Nutzer keinen großen Vorteil. In den folgenden Schritten deaktivieren Sie das Symbol und lassen nur eine Benachrichtigung für den Eieruhr-Timer anzeigen.

  1. Fügen Sie dem Code zum Erstellen des Channels setShowBadge(false) hinzu, um Badges zu deaktivieren.
// EggTimerFragment.kt

    ).apply {
        // TODO: Step 2.6 disable badges for this channel
        setShowBadge(false)
    }
  1. Führen Sie die App noch einmal aus, starten Sie den Timer und beobachten Sie das App-Symbol. Auf dem App-Symbol sollten keine Badges zu sehen sein.

Der Lösungscode befindet sich im Master-Branch des heruntergeladenen Codes.

Udacity-Kurs:

Android-Entwicklerdokumentation:

Links zu anderen Codelabs in diesem Kurs finden Sie auf der Landingpage für Codelabs zum Thema „Android für Fortgeschrittene mit Kotlin“.