To ćwiczenie programowania jest częścią kursu „Android dla zaawansowanych w Kotlinie”. Korzyści z tego kursu będą dla Ciebie najbardziej wartościowe, jeśli wykonasz je w sekwencjach ćwiczeń z programowania, ale nie jest to obowiązkowe. Wszystkie ćwiczenia z kursu są wymienione na stronie Zaawansowane ćwiczenia z programowania na Androida w Kotlin.
Wstęp
Powiadomienia to wiadomości pokazywane użytkownikowi poza interfejsem aplikacji. Powiadomienia są wyświetlane u góry ekranu, jeśli urządzenie jest odblokowane lub, w zależności od ustawień zabezpieczeń, na ekranie blokady, gdy urządzenie jest zablokowane.
Typowe powiadomienie składa się z tytułu, opisu i ikony. Powiadomienie może też zawierać działania, które można kliknąć, krótką odpowiedź, treść, którą można rozwinąć, i obrazy.
Powiadomienia mogą szybko dostarczać materiały, a klienci mogą używać przycisków umożliwiających użytkownikowi wykonywanie szybkich działań, takich jak wysłanie odpowiedzi czy odłożenie alarmu. Kliknięcie powiadomienia powoduje przejście do widoku w aplikacji powiązanego z treścią powiadomienia.
Dzięki powiadomieniom możesz powiadomić użytkowników o ważnym zadaniu, poinformować ich o wystąpieniu lub poinformować ich o ważnych zmianach, gdy aplikacja działa w tle. Nie nadużywaj powiadomień. Nie tylko szanuje to użytkowników, ale również zwiększa prawdopodobieństwo, że Twoja aplikacja zasługuje na to, na co zasługuje.
Z tego modułu dowiesz się, jak tworzyć i używać powiadomienia w aplikacji na Androida.
Co musisz wiedzieć
Pamiętaj:
- Jak tworzyć aplikacje na Androida w Kotlinie. Szczególnie dotyczy to pakietu Android SDK.
- Jak łączyć architekturę aplikacji za pomocą komponentów architektury i wiązania danych.
- Podstawowe informacje o BroadcastBroadcastReceive
- Podstawowe informacje o usłudze AlarmManager
Czego się nauczysz
- jak tworzyć i wysyłać powiadomienia oraz określać ich styl;
- Jak anulować powiadomienia.
- Tworzenie kanałów powiadomień
- Jak dodawać szybkie działania do powiadomień
- Wyświetlanie plakietek z powiadomieniem na ikonie aplikacji
Jakie zadania wykonasz:
- Dodaj powiadomienie do aplikacji startowej.
- Anuluj wysłane wcześniej powiadomienie.
- Twórz kanały dla różnych typów powiadomień.
- Dostosuj powiadomienia w aplikacji startowej.
- Dodaj szybkie działania, aby powiadomienie stało się interaktywne.
- Wyłącz plakietki z powiadomieniami.
Przygotowywanie jaj jest proste, ale może się okazać wyzwaniem, jeśli nie potrafisz go kontrolować. W tym ćwiczeniu będziesz pracować nad aplikacją jajka z licznikiem czasu, która pomoże sprawić, by jajka wyglądały jak prawdziwe. Uruchomiona zostanie aplikacja działającego minutnika jaj, która daje użytkownikowi możliwość ustawienia różnych ustawień czasu gotowania dla różnych stylów jaj. Minutnik odlicza od wybranego przedziału czasu i wyświetla komunikat, gdy jajka będą gotowe.
Może się wydawać, że działa, ale wcale nie jest idealna i niezbyt przyjazna użytkownikowi. Po pierwsze, komunikat wyświetla się tylko przez krótki czas i dlatego można go łatwo pominąć. Ponadto, jeśli aplikacji nie ma na pierwszym planie lub urządzenie jest zablokowane, nie pojawi się wskaźnik wizualny stanu minutnika po zniknięciu komunikatu.
Najlepiej, gdyby minutnik jajka pokazywał się użytkownikom, kiedy czas dobiega końca. Użytkownik musi wiedzieć, że jajka są od razu gotowe, w przeciwnym razie będą się gotować. Powiadomienia mają charakter wizualny, mogą zawierać dźwięki i sprawić, że urządzenie zacznie wibrować, a przyciągnie ono uwagę użytkownika. W ten sposób przygotujesz doskonałe jajka, które będą uspokoić użytkowników.
Możesz pobrać aplikację próbną na dwa sposoby:
Skopiuj repozytorium z GitHuba i przejdź do gałęzi starter.
$ git clone https://github.com/googlecodelabs/android-kotlin-notifications
Możesz też pobrać repozytorium jako plik ZIP, rozpakować go i otworzyć w Android Studio.
- Otwórz i uruchom aplikację w Android Studio.
Pojawi się menu jajka i menu z gotową listą gotowych przedziałów czasowych, w których można ugotować jajko. Kliknij trójkąt w menu Miękkie gotowane. Pierwsza opcja na liście służy do testowania i ustawia alarm na 10 sekund. Obok listy znajduje się przełącznik, który uruchamia minutnik jaj. W każdej chwili możesz użyć tego przełącznika, aby włączać i wyłączać minutnik jaj. Kod początkowy jest w pełni funkcjonalny, co oznacza, że możesz skonfigurować licznik czasu jajka i odliczać do 0. Po zakończeniu odliczania zostanie wyświetlony komunikat.
- Sprawdź kod źródłowy. Aplikacja startowa składa się z pojedynczej aktywności o nazwie
MainActivity
. Dostępne są 3 podpakiety o nazwachreceiver
,ui
iutil
.
- /odbiornik – pakiet
receiver
zawiera 2 odbiorniki o nazwieAlarmReceiver
iSnoozeReceiver
.AlarmReceiver
uruchamia się, gdyAlarmManager
wysyła powiadomienie, gdy licznik czasu zdefiniowany przez użytkownika minie. Aby odłożyć powiadomienie, użytkownik musi kliknąćSnoozeReceiver
. - /ui – zawiera
EggTimerFragment
, który jest częścią interfejsu aplikacji.EggTimerViewModel
odpowiada za uruchamianie i anulowanie minutnika oraz za inne zadania związane z cyklem życia aplikacji. - /util – w tym pakiecie znajdują się dwa pliki.
BindingUtils.kt
ma adaptery wiązania, które umożliwiają wiązanie danych między interfejsem aplikacji aViewModel
.NotificationUtils.kt
udostępnia metody rozszerzeń naNotificationManager
.
Użycie powiadomień to świetny sposób na przyciągnięcie uwagi użytkowników aplikacji. Bez względu na to, czy aplikacja działa czy nie działa na pierwszym planie, powiadomienie wyświetli wyskakujące okienko, które może zawierać dźwięk lub wibracje. Aby utworzyć powiadomienie, musisz użyć kreatora powiadomień oraz podać tekst tytułu, treść i ikonę. Gdy konstruktor ma wszystkie wymagane pola, NotificationManager
, czyli usługa systemowa, umożliwia wyświetlanie tych treści jako powiadomień. NotificationManager
odpowiada za wysłanie powiadomienia, zaktualizowanie jego treści i anulowanie powiadomienia. W kolejnych krokach dodasz metody rozszerzeń do NotificationManager
. Dzięki temu za każdym razem, gdy zechcesz skorzystać z NotificationManager
, będziesz mieć możliwość skorzystania z tych funkcji rozszerzeń, aby uzyskać niezbędne funkcje.
Krok 1. Utwórz podstawowe powiadomienie
W tym zadaniu tworzysz nowe powiadomienie, ustawiasz wiadomość dla użytkownika i wysyłasz powiadomienie.
- Otwórz klasę
NotificationUtils.kt
i znajdź opcjęTODO: Step 1.1
. Zadania do wykonania znajdziesz w tym ćwiczeniu z programowania i w kodzie aplikacji. - Sprawdź daną funkcję
sendNotification()
. Rozszerzysz tę funkcję rozszerzenia oNotificationManager
, aby wysyłać powiadomienia.
//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) {
- Pobierz wystąpienie kreatora powiadomień, przekaż kontekst aplikacji i identyfikator kanału. Identyfikator kanału jest ciągiem znaków.
Kanały powiadomień umożliwiają grupowanie powiadomień. Łącząc podobne typy powiadomień, deweloperzy i użytkownicy mogą kontrolować wszystkie powiadomienia na kanale. Po utworzeniu kanału możesz używać go do wysyłania dowolnej liczby powiadomień.
//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)
)
- Ustaw ikonę powiadomienia, aby reprezentować aplikację, tytuł oraz tekst treści wiadomości, którą chcesz przekazać użytkownikowi. W ćwiczeniach z programowania zobaczysz więcej opcji dostosowywania powiadomienia, ale jest to minimalna ilość danych, które musisz ustawić, aby wysłać powiadomienie.
//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)
- Następnie musisz wywołać
notify()
za pomocą unikalnego identyfikatora powiadomienia i obiektuNotification
z konstruktora.
Ten identyfikator reprezentuje bieżącą instancję powiadomienia i jest potrzebny do zaktualizowania lub anulowania tego powiadomienia. Twoja aplikacja będzie miała tylko jedno aktywne powiadomienie, więc możesz używać tego samego identyfikatora dla wszystkich powiadomień. Masz już stałą wartość o nazwie NOTIFICATION_ID
w NotificationUtils.kt
. Zauważ, że możesz wywołać funkcję notify()
bezpośrednio, ponieważ wykonujesz połączenie z funkcji rozszerzenia w tej samej klasie.
//NotificationUtils.kt
// TODO: Step 1.4 call notify to send the notification
// Deliver the notification
notify(NOTIFICATION_ID, builder.build())
- Otwórz
ui/EggTimerViewModel.kt
i znajdź funkcjęstartTimer()
. Ta funkcja tworzy alarm z wybranym przedziałem czasu, gdy użytkownik włączy minutnik. - Gdy użytkownik uruchomi minutnik, wyświetli się powiadomienie w tej funkcji. Aby wywoływać funkcję
sendNotification()
, która została wcześniej zaimplementowana, potrzebujesz wystąpieniaNotificationManager
.NotificationManager
to usługa systemowa, która udostępnia wszystkie funkcje interfejsu API powiadomień, w tym funkcję dodanego rozszerzenia. Jeśli chcesz wysłać, anulować lub zaktualizować powiadomienie, musisz poprosić o wystąpienie elementuNotificationManager
w systemie. Wywołaj funkcjęsendNotification()|
z powiadomieniem i kontekstem.
// 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)
Prawie Ci się udało! Jeśli jednak uruchomisz aplikację teraz i ustawisz minutnik, nie otrzymasz powiadomienia.
- Otwórz aplikację
logcat
i wyszukaj:"No Channel found"
. Powinien wyświetlić się komunikat o błędzie informujący, żeegg_channel
nie istnieje. Aby rozwiązać ten problem, wykonaj czynności opisane poniżej.
Krok 2. Kanały powiadomień
Począwszy od poziomu API 26, wszystkie powiadomienia muszą być przypisane do kanału. Jeśli naciśniesz i przytrzymasz ikonę programu uruchamiającego, wybierzesz informacje o aplikacji i klikniesz powiadomienia, zobaczysz listę kanałów powiadomień powiązanych z aplikacją. Obecnie lista jest pusta, ponieważ aplikacja nie utworzyła żadnych kanałów.
Kanały oznaczają &typ powiadomienia – na przykład stoper z jajkiem może wysłać Ci powiadomienie, gdy jajko się zagotuje, a codziennie wysyłać kolejne powiadomienia, by przypominać Ci o śniadaniu. Wszystkie powiadomienia na kanale są grupowane, a użytkownicy mogą konfigurować ustawienia powiadomień dla całego kanału. Dzięki temu użytkownicy mogą spersonalizować ustawienia powiadomień, biorąc pod uwagę rodzaj powiadomień, które ich interesują. Użytkownicy mogą na przykład wyłączyć powiadomienia o śniadaniu, ale nadal chcą otrzymywać powiadomienia z minutnika.
Deweloperzy określają wstępne ustawienia, znaczenie i zachowanie stosowane do wszystkich powiadomień w kanale. Gdy skonfigurujesz ustawienia początkowe, użytkownicy mogą je zastąpić.
W kroku 1.1 jako kanał powiadomień wybrano egg_notification_channel_id
, więc teraz musisz samodzielnie utworzyć i dostosować ustawienia powiadomień oraz sposób działania tego kanału.
- Otwórz
EggTimerFragment.kt
i znajdź funkcjęcreateChannel()
. - Przekaż unikalny identyfikator kanału konstruktorowi
NotificationChannel
. - Przekaż nazwę kanału powiadomień, którą użytkownicy zobaczą też na ekranie Ustawienia.
- Jako ostatni parametr, którego poziom ważności jest wymagany w przypadku kanału powiadomień. Poziomy ważności zostaną omówione w dalszej części tego ćwiczenia, więc na razie możesz użyć
NotificationManag
er.IMPORTANCE_LOW
. - W obiekcie
notificationChannel
ustaw wartość „enableLights
” na „true”. To ustawienie włączy diody po wyświetleniu powiadomienia. - Na
notificationChannel
obiekcielightColor
ustawionym na czerwono, aby pojawiło się czerwone światło po wyświetleniu powiadomienia. - Aby włączyć wibracje, w obiekcie
notificationChannel
ustaw wartość „enableVibration
” na „true”. - W obiekcie
notificationChannel
ustaw opis kanału na‘Time for breakf
ast'. - Uzyskaj instancję
NotificationManager
przez wywołanie metodygetSystemService()
. - Wywołaj
createNotificationChannel()
w obiekcieNotificationManager
i przekaż obiektnotificationChannel
utworzony w poprzednim kroku.
//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
}
- Aby utworzyć kanał, musisz wywołać utworzoną funkcję
createChannel()
(krok 1.7). Funkcja ta wykorzystuje 2 parametry: identyfikator i nazwę kanału. Identyfikator i nazwę kanału musisz wyszukać w zasobach ciągu znaków podanych już w Twoim projekcie.
// EggTimerFragment.kt
// TODO: Step 1.7 call createChannel
createChannel(
getString(R.string.egg_notification_channel_id),
getString(R.string.egg_notification_channel_name)
)
- Musisz przekazać identyfikator kanału do kreatora powiadomień. Ta czynność została już wykonana w kroku 1.2. Ustawienie niewłaściwej wartości spowoduje, że powiadomienie nie powiedzie się. Otwórz
NotificationUtils.kt
, aby sprawdzić, czy wcześniej ustawiony identyfikator kanału jest prawidłowy.
// NotificationUtils.kt
val builder = NotificationCompat.Builder(
applicationContext,
// TODO: Step 1.8 verify the notification channel name
applicationContext.getString(R.string.egg_notification_channel_id)
)
- Uruchom aplikację. Zobaczysz powiadomienie przy każdym uruchomieniu minutnika.
- Pociągnij pasek stanu i sprawdź, czy tytuł, treść i ikona powiadomienia są ustawione tak jak w poprzednich krokach.
- Aby sprawdzić informacje o nowo utworzonym kanale, zamknij aplikację i znajdź ikonę aplikacji. Przytrzymaj ikonę aplikacji i wybierz Informacje o aplikacji.
- Z listy ustawień wybierz Powiadomienia. Pod ustawieniem Pokaż powiadomienia powinien być widoczny nowy kanał o nazwie Jajko.
Powiadomienie pojawi się po uruchomieniu aplikacji. Zarówno Ty, jak i deweloper aplikacji, możecie dostosować ustawienia i zachowanie wszystkich powiadomień wysyłanych na ten kanał. Gratulacje, powiadomienie zostało utworzone!
Krok 3. Dodaj powiadomienia do aplikacji
Na razie pokazano podstawy korzystania z interfejsu API powiadomień, ale wysyłanie powiadomienia zaraz po uruchomieniu minutnika nie ma sensu. Użytkownicy wolą otrzymywać powiadomienia, gdy jajko będzie gotowe. W następnej części ćwiczeń z programowania dowiesz się, jak to naprawić, i wymienisz toast na powiadomienie.
Powiadomienie zostało już wysłane i zgłoszone użytkownikom zostało wyświetlone, ale to był tylko pierwszy krok do utworzenia świetnych powiadomień. W tym kroku zmienisz ustawienia powiadomień, by wysyłane w odpowiednim momencie.
Twoja aplikacja używa AlarmManager
do konfigurowania alarmu. Kod związany z AlarmManager
jest już zawarty w kodzie początkowym i jest używany do wyświetlania komunikatu. AlarmManager
śledzi wybraną godzinę i aktywuje funkcję onReceive()
AlarmReceiver.kt
po zakończeniu. Jeśli otworzysz aplikację AlarmReceiver.kt
i przejdziesz do sekcji onReceive()
, powinien się wyświetlić komunikat, który pojawia się za każdym razem, gdy ustawisz minutnik.
- Otwórz
AlarmReceiver.kt
(wystąpienieNotificationManager
) i wywołaj funkcjęsendNotification()
z tekstem wiadomości oraz parametrami kontekstowymi.
// 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
)
- Możesz też usunąć to powiadomienie, ponieważ po zakończeniu minutnika aplikacja zacznie wysyłać powiadomienia.
// AlarmReceiver.kt
// TODO: Step 1.10 [Optional] remove toast
// Toast.makeText(
// context,
// context.getText(R.string.eggs_ready),
// Toast.LENGTH_SHORT
// ).show()
- Uruchom aplikację . Takie powiadomienie jest wyświetlane za każdym razem, gdy uruchomisz minutnik lub po jego upływie.
Nie jest to idealne rozwiązanie. Nie chcesz wysyłać zbyt wielu powiadomień do użytkowników. Możesz usunąć pierwsze powiadomienie, które jest wysyłane, gdy użytkownik uruchomi minutnik.
- Otwórz aplikację
EggTimerFragment.kt
i usuń kod powiadomienia z kroku 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)
- Uruchom ponownie aplikację.
- Ustaw minutnik, umieść go w tle i zaczekaj, aż się zakończy. Zobaczysz powiadomienie. To powiadomienie jest dużo bardziej przydatne.
Krok 4. Dodaj intencję treści
- Uruchom aplikację ponownie, jeśli jeszcze nie jest uruchomiona.
- Kliknij powiadomienie. Nic się nie dzieje.
Wyświetlanie powiadomienia i informowanie go jest świetne, ale gdy użytkownik kliknie powiadomienie, spodziewa się, że wróci do odpowiedniej aplikacji. W ramach ćwiczenia z programowaniem dodasz do powiadomienia zamiar, by wyświetlić go na ekranie licznika.
Element Intent
to obiekt wiadomości, którego możesz użyć, aby zażądać działania z innego komponentu aplikacji. Intencje mogą być używane do uruchamiania działania, usługi lub dostarczania wiadomości. W takim przypadku ten system służy do informowania systemu, że gdy użytkownik kliknie powiadomienie, ma otwierać MainActivity
. Aplikacja składa się tylko z jednego widoku, więc nie masz tu zbyt wielu opcji. Jednak w większej aplikacji powiadomienie powinno zapewnić użytkownikowi płynny obraz i skierować go na ekran odpowiedni do interakcji z powiadomieniem.
- Otwórz
NotificationUtils.kt
i znajdź funkcję rozszerzeniasendNotification()
. - Utwórz
Intent
zapplicationContext
i rodzajem aktywności, którą chcesz uruchomić,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)
Została przez Ciebie utworzona intencja, ale w aplikacji pojawiło się powiadomienie. Jeśli chcesz, aby intencje działały poza aplikacją, musisz utworzyć nową grupę PendingIntent
.
PendingIntent
przyznaje prawo do innej aplikacji lub systemu do wykonywania operacji w imieniu Twojej aplikacji. Element PendingIntent
jest tylko odwołaniem do tokena przechowywanego przez system opisujący pierwotne dane użyte do jego pobrania. Oznacza to, że nawet jeśli proces tworzenia aplikacji zostanie zakończony, PendingIntent
nadal będzie można go używać na potrzeby innych procesów, którym go przydzielono. W takim przypadku system będzie uruchamiać aplikację w Twoim imieniu, niezależnie od tego, czy działa minutnik.
- Utwórz
PendingIntent
zapplicationContext
,NOTIFICATION_ID
,contentIntent
utworzonym w poprzednim kroku i flagąPendingIntent
. FlagaPendingIntent
określa opcję tworzenia nowego obiektuPendingIntent
lub używania istniejącego. Musisz ustawićPendingIntent.FLAG_UPDATE_CURRENT
jako flagę, ponieważ nie chcesz tworzyć nowego powiadomienia, jeśli już istnieje. W ten sposób zmienisz obecny elementPendingIntent
powiązany z intencją intencji.
// NotificationUtils.kt
// TODO: Step 1.12 create PendingIntent
val contentPendingIntent = PendingIntent.getActivity(
applicationContext,
NOTIFICATION_ID,
contentIntent,
PendingIntent.FLAG_UPDATE_CURRENT
)
- Przekaż
PendingIntent
w powiadomieniu. Aby to zrobić, zadzwoń pod numersetContentIntent()
w aplikacjiNotificationBuilder
. Teraz gdy klikniesz powiadomienie, wyświetli sięPendingIntent
–MainActivity
otworzy się. - Możesz też ustawić
setAutoCancel()
natrue
– gdy użytkownik kliknie powiadomienie, otworzy się samo przejście do aplikacji.
// NotificationUtils.kt
// TODO: Step 1.13 set content intent
.setContentIntent(contentPendingIntent)
.setAutoCancel(true)
- Ponownie uruchom aplikację.
- Ustaw minutnik, umieść aplikację w tle i zaczekaj, aż pojawi się powiadomienie.
- Gdy pojawi się powiadomienie, kliknij je, przesuwając w dół pasek stanu. Zobaczysz, jak aplikacja działa na pierwszym planie.
Krok 5. Anuluj powiadomienie
Masz ustawiony funkcjonalny minutnik jajka z powiadomieniami. Wystąpił mały problem. Jeśli ustawisz minutnik, otrzymasz powiadomienie i ponownie ustawisz minutnik, poprzednie powiadomienie pozostanie na pasku stanu podczas działania nowego minutnika. Może to dezorientować użytkowników, jeśli aplikacja działa w tle, co może doprowadzić do niedogotowania jaj.
Aby rozwiązać ten problem, musisz wyczyścić poprzednie powiadomienie po uruchomieniu nowego minutnika. Zacznij od utworzenia innej funkcji rozszerzenia w NotificationUtils.kt
. NotificationManager
ma interfejs API do anulowania wszystkich aktywnych powiadomień o nazwie cancelAll
()
.
- Otwórz aplikację
NotificationsUtil.kt
. - Dodaj do
NotificationManager
funkcję rozszerzenia, która wywołujecancelAll()
.
// NotificationUtils.kt
// TODO: Step 1.14 Cancel all notifications
/**
* Cancels all notifications.
*
*/
fun NotificationManager.cancelNotifications() {
cancelAll()
}
- Otwórz aplikację
EggTimerViewModel.kt
i przejdź do funkcjistartTimer()
. - W ramach
startTimer()
pobierz z systemu wystąpienieNotificationManager
i wywołajcancelNotifications()
.
// EggTimerViewModel.kt
//TODO Step 1.15 call cancel notification
val notificationManager =
ContextCompat.getSystemService(
app,
NotificationManager::class.java
) as NotificationManager
notificationManager.cancelNotifications()
- Uruchom aplikację i włącz minutnik.
- Gdy pojawi się powiadomienie, ponownie włącz licznik czasu i sprawdź, jak nasza aplikacja automatycznie usuwa poprzednie powiadomienie z paska stanu.
Platforma powiadomień daje programistom różne opcje dostosowywania działań niestandardowych i stylu ich powiadomień. Z tego zadania dowiesz się, jak dostosować powiadomienia minutnika jaj.
Krok 1. Dostosuj styl powiadomienia
Wygląd powiadomienia możesz dostosować do swoich potrzeb, a jego treść sprawi, że powiadomienia będą się wyróżniać i wyglądają jak rozszerzenie aplikacji. Platforma powiadomień zawiera kilka wbudowanych stylów, które mogą pomóc w tworzeniu kreacji.
NotificationCompat
ma wbudowane style dla:
BigTextStyle
, która może wyświetlać duży blok tekstu, na przykład po rozwinięciu treści e-maila.BigPictureStyle
, który wyświetla powiadomienia o dużym formacie zawierające duży załącznik.InboxStyle
, która zawiera tekst rozmowy.MediaStyle
, który zawiera elementy sterujące odtwarzaniem multimediów.MessagingStyle
, gdzie wyświetlane są powiadomienia w dużym formacie zawierające wiele wiadomości wysyłanych przez dowolną liczbę osób.
Więcej informacji o innych stylach znajdziesz w dokumentacji dotyczącej tworzenia powiadomień rozwijanych. W tym kroku użyjesz NotificationCompat.BigPictureStyle
, aby utworzyć rozwijane powiadomienie, które po rozwinięciu będzie wyświetlać duże zdjęcie jajka.
- Otwórz
NotificationUtils.kt
i znajdź funkcjęsendNotification()
. - Zacznij od wczytania obrazu ze strony
resources
za pomocąBitmapFactory
.
// NotificationUtils.kt
// TODO: Step 2.0 add style
val eggImage = BitmapFactory.decodeResource(
applicationContext.resources,
R.drawable.cooked_egg
)
- Utwórz nowy plik
BigPictureStyle
i ustaw zdjęcie. - Ustaw
bigLargeIcon()
jakonull
, aby po rozwinięciu powiadomienia zniknęła duża ikona.
// 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)
- Ustaw styl z
setStyle()
nabigPicStyle
. - Ustaw dużą ikonę
setLargeIcon()
naeggImage
, aby po zwinięciu powiadomienia było ono wyświetlane jako mniejsza ikona.
// NotificationUtils.kt
// TODO: Step 2.1 add style to builder
.setStyle(bigPicStyle)
.setLargeIcon(eggImage)
- Uruchom aplikację i ustaw minutnik. Gdy powiadomienie jest wyświetlane po raz pierwszy, jest wyświetlane w szufladzie powiadomień w stanie zwiniętym. Gdy rozwiniesz powiadomienie, w obszarze rozwiniętym pojawi się duży obraz.
Krok 2. Powiadomienie
Działania związane z powiadomieniami to kolejne dostosowanie, które możesz dostosować do swoich powiadomień. Powiadomienia są obecnie przekierowywane do aplikacji po kliknięciu jej przez użytkownika. Oprócz tego domyślnego działania powiadomień możesz dodać przyciski, które pozwalają wykonywać zadania związane z powiadomieniami z poziomu powiadomienia.
Powiadomienia mogą zawierać maksymalnie 3 przyciski czynności, które umożliwiają użytkownikowi szybką reakcję, na przykład odłożenie przypomnienia lub wysłanie SMS-a. Te przyciski działań nie powinny powielać czynności wykonywanych, gdy użytkownik kliknie powiadomienie.
Aby dodać przycisk działania, przekaż PendingIntent
do funkcji addAction()
w kreatorze. To działanie jest podobne do konfigurowania domyślnego działania powiadomienia przez wywołanie funkcji setContentIntent()
. Różnica polega na tym, że zamiast uruchamiać aktywność, możesz wykonać inne czynności, na przykład uruchomić BroadcastReceiver
, który wykonuje zadanie w tle, aby nie przerywać działania aplikacji, która jest już otwarta.
W ramach tych ćwiczeń masz już BoadcastReceiver
o nazwie SnoozeReceiver
. Wykorzystasz SnoozeReceiver
, aby poprosić użytkownika o kliknięcie działania powiadomienia. W kolejnych krokach dodasz kod, który spowoduje odłożenie powiadomienia minutnika na 60 sekund po kliknięciu przycisku drzemki. Po kliknięciu działania drzemki SnoozeReceiver
otrzyma intencję i utwórz nowy alarm, aby po 60 sekundach wysłać nowe powiadomienie.
- Otwórz aplikację
SnoozeReceiver.kt
. Te zajęcia są podobne do tych, których używałeś wcześniej w ramach:AlarmReceiver
. W kolejnych krokach dodasz kod, który wywoła funkcjęonReceive()
elementuSnoozeReceiver
. Krótko mówiąc, kod w usłudzeSnoozeReceiver
utworzy nowy alarm, który pozwoli wysłać nowe powiadomienie minutę później. Przewiń widok w dół funkcji onReceive, pobierz wystąpienie powiadomienia z Menedżera systemu i wywołaj funkcję anulowaćAll.
// SnoozeReceiver.kt
val notificationManager = ContextCompat.getSystemService(
context,
NotificationManager::class.java
) as NotificationManager
notificationManager.cancelAll()
- Aby użyć aplikacji
SnoozeReceiver
, otwórz aplikacjęNotificationUtils.kt
. - Utwórz nowy
Intent
snoozeIntent
dla elementuSnoozeReceiver
tuż za stylem w funkcjisendNotification()
. - Utwórz oczekującą intencję, wywołując metodę
getBroadcast()
w obiekciePendingIntent
, która wymaga parametrów wymienionych w kolejnych krokach. SystemPendingIntent
będzie używać tego systemu do konfigurowania nowego alarmu w celu opublikowania nowego powiadomienia po 60 sekundach po kliknięciu przez użytkownika przycisku drzemki. - Pierwszy parametr to kontekst aplikacji, w którym
PendingIntent
ma rozpoczynać działanie. - Drugi parametr to kod żądania, czyli kod żądania dla tej intencji. Jeśli chcesz zaktualizować lub anulować oczekującą intencję, musisz użyć tego kodu, aby uzyskać dostęp do oczekującej intencji.
- Następnie dodaj obiekt
snoozeIntent
będący celem uruchamiania aktywności. - Na koniec dodaj wartość flagi
#FLAG_ONE_SHOT
, ponieważ intencja zostanie użyta tylko raz. Szybkie działanie i powiadomienie znikną po pierwszym kliknięciu. Z tego powodu intencji można użyć tylko raz.
// 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
)
- Następnie wywołaj funkcję
addAction()
wnotificationBuilder
. Ta funkcja oczekuje, że ikona i tekst opisują działanie użytkownika. Musisz też dodaćsnoozeIntent
. Ta intencja zostanie użyta do wywołania odpowiedniego elementuboadcastReceiver
po kliknięciu działania.
// NotificationUtils.kt
// TODO: Step 2.3 add snooze action
.addAction(
R.drawable.egg_icon,
applicationContext.getString(R.string.snooze),
snoozePendingIntent
)
- Uruchom aplikację minutnika, aby włączyć drzemkę.
- Uruchom minutnik i umieść aplikację w tle. Po upływie tego czasu rozwiń powiadomienie, a zobaczysz, że zawiera on przycisk drzemki, który włączy drzemkę na następną minutę.
Krok 3. Znaczenie powiadomienia
Znaczenie określa, w jakim stopniu powiadomienie powinno zakłócić wzrok i dźwięk. Powiadomienia o większym znaczeniu będą bardziej uciążliwe dla użytkowników.
Musisz określić poziom ważności w konstruktorze NotificationChannel
. Ta aplikacja była bardzo mała. Możesz użyć jednego z pięciu poziomów ważności: od IMPORTANCE_NONE(0)
do IMPORTANCE_HIGH(4)
. Poziom ważności przypisany kanałowi ma zastosowanie do wszystkich publikowanych na nim wiadomości z powiadomieniami.
Poziomy ważności kanału
Poziom ważności widoczny dla użytkowników | Ważność (Android 8.0 i nowsze) | Priorytet (Android 7.1 i starsze) |
Wydaje dźwięk i wyświetla się jako powiadomienie z ostrzeżeniem (pojawia się w górnej części ekranu) | ||
Wydaje dźwięk | ||
Brak dźwięku | ||
Brak dźwięku i nie pojawia się na pasku stanu |
Więcej informacji o wybieraniu odpowiedniego poziomu priorytetu znajdziesz w Przewodniku po projektowania powiadomień. Zachowaj ostrożność, wybierając poziom ważności powiadomień w aplikacji. Ważne jest, aby wybrane kanały były uwzględniane pod kątem czasu i uwagi użytkownika. Nieistotne powiadomienie udające się jako pilne, może wywołać niepotrzebne alarmy i rozproszyć uwagę. Użytkownicy mają pełną kontrolę nad poziomem ważności powiadomień, więc jeśli tworzysz irytujące powiadomienie, mogą oni całkowicie wyłączyć Twój kanał powiadomień.
Gdy po raz pierwszy udało Ci się utworzyć powiadomienie w kroku 1.6, licznik jaj został ustawiony, by wysyłać powiadomienia o niskim priorytecie, bo nie ma ono wpływu na powiadomienia użytkownika. Dobrym pomysłem może być jednak przyciągnięcie uwagi użytkownika, zanim jajko się nie zsunie. Aby zmienić poziom ważności powiadomienia, zacznij od ustawień kanału. Znaczenie kanału ma wpływ na poziom wszystkich powiadomień publikowanych na kanale i musi być określony w konstruktorze NotificationChannel
.
- Aby zmienić poziom ważności kanału powiadomień aplikacji, otwórz
EggTimerFragment.kt
i przejdź na stronęcreateChannel()
. Zmień poziom ważności zIMPORTANCE_LOW
naIMPORTANCE_HIGH
.
// EggTimerFragment.kt
val notificationChannel = NotificationChannel(
channelId,
channelName,
// TODO: Step 2.4 change importance
NotificationManager.IMPORTANCE_HIGH
)
Aby obsługiwać urządzenia z Androidem 7.1 (poziom API 25) lub starszym, musisz też wywołać setPriority()
dla każdego powiadomienia, używając stałej priorytetu klasy NotificationCompat
.
- Otwórz
NotificationUtils.kt
i dodaj do obiektu narzędzia do tworzenia powiadomień:
// 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)
- Zanim uruchomisz aplikację, przytrzymaj jej ikonę na urządzeniu lub w emulatorze i wybierz Odinstaluj, by wyczyścić poprzednie ustawienia kanału. Jeśli nie odinstalujesz aplikacji, ustawienia priorytetu kanału nie ulegną zmianie i nie spowoduje to zmiany działania po opublikowaniu powiadomienia.
- Ponownie uruchom aplikację i włącz minutnik. Tym razem po wysłaniu powiadomienia u góry ekranu powinno pojawić się wyskakujące okienko, niezależnie od tego, czy działa ono na pierwszym planie czy w tle.
Krok 4. Plakietki powiadomień
Plakietki powiadomień to małe kropki wyświetlane na ikonie programu uruchamiającego powiązanej aplikacji, gdy aplikacja ma aktywne powiadomienie. Użytkownicy mogą przycisnąć i przytrzymać ikonę aplikacji, aby wyświetlić powiadomienia.
Te plakietki, zwane plakietkami, są wyświetlane domyślnie. Nie musisz nic robić w aplikacji. Może się jednak zdarzyć, że plakietki nie mają sensu dla powiadomień. Możesz je wyłączyć w poszczególnych kanałach, wywołując setShowBadge(false)
na obiekcie NotificationChannel
. Minutnik jajka ma tylko jedno aktywne powiadomienie w danym momencie, dlatego plakietka na ikonie aplikacji nie przynosi żadnych korzyści użytkownikom. W kolejnych krokach wyłączymy plakietkę i wyświetlimy tylko powiadomienie dotyczące minutnika jaj.
- Dodaj
setShowBadge(false)
do kodu tworzenia kanału, aby wyłączyć plakietki w przypadku licznika czasu.
// EggTimerFragment.kt
).apply {
// TODO: Step 2.6 disable badges for this channel
setShowBadge(false)
}
- Ponownie uruchom aplikację, włącz minutnik i obejrzyj jej ikonę. Na ikonie aplikacji nie powinny być widoczne żadne odznaki.
Kod rozwiązania znajduje się w gałęzi głównej pobranego kodu.
- Użyj klasy NotificationManager, by utworzyć, wysłać, zaktualizować i anulować powiadomienie za pomocą.
- Aby określić kanał powiadomień, użyj obiektu NotificationChannel z metodą createNotificationChannel.
- Użyj funkcji addAction(), aby dodać szybkie powiadomienie do powiadomienia.
- Użyj funkcji setShowBadge(), aby włączyć lub wyłączyć plakietki.
- Dostosuj styl powiadomień, używając stylów, które obejmuje też tryb Notification.Style.
- Ustaw poziom ważności za pomocą funkcji NotificationChannel.setImportance().
Kurs Udacity:
Dokumentacja dla programistów Androida:
Linki do innych ćwiczeń z programowania znajdziesz w kursie dotyczącym programowania na Androida dla zaawansowanych w Kotlin.