Powiadomienia w systemie Android Powiadomienie to krótka wiadomość, która pozwala informować użytkownika o pewnych wydarzeniach pochodzących z aplikacji - będąc poza nią. Wykorzystane w odpowiedni sposób może znacznie zwiększyć atrakcyjność naszej aplikacji. Wszyscy przyzwyczailiśmy się już do tego mechanizmu. Wiele aplikacji na bieżąco zasypuje nas różnymi powiadomieniami. Trudno byłoby dziś wyobrazić sobie brak otrzymania informacji o nadesłanej wiadomości SMS/MMS, e-mail, czy powiadomienia o wydarzeniu z kalendarza. W wersji Androida Jelly Bean bardzo rozbudowano system powiadomień udostępniając wiele ciekawych funkcjonalności takich jak: ustawianie dodatkowych akcji dla powiadomienia, nowy rozszerzony widok wiadomości mogący zawierać dodatkowe informacje, a nawet bitmapy, ustawianie priorytetu powiadomienia, Wszystkie te możliwości zaprezentowane zostały poniżej. Zastosowanie Najczęściej spotykane zastosowania powiadomień to informowanie użytkownika o: nadejściu wiadomości tekstowej lub wiadomości e-mail, nieodebranych połączeniach telefonicznych, nadchodzącym wydarzeniu z kalendarza, postępie pobierania danych z zewnętrznych źródeł, aktualizacji aplikacji. Typy powiadomień Od wersji Androida 4.1 istnieją dwa typy prezentacji powiadomienia. Pierwszy to widok normalny, złożony z sześciu elementów. 1. tytuł powiadomienia 2. duża ikony 3. treść powiadomienia 4. liczba zgrupowanych powiadomień 5. mała ikona 6. czas powiadomienia Drugi to tak zwany duży widok. Składa się on z tych samych elementów co widok normalny ale posiada dodatkowy obszar (7), który może zawierać szczegółowe informacje o wiadomości i może być wyświetlany, w zależności od zastosowania, w trzech trybach wizualnych: Big picture style prezentowanie bitmapy o wysokości do 256dp, Big text style wyświetlanie dużego bloku tekstu, Inbox style wyświetlanie tekstu w postaci oddzielnych linii.
Tworzenie prostego powiadomienia W ramach prezentacji możliwości mechanizmu powiadomień zostanie stworzony jeden projekt, do którego będą kolejno dodawane nowe funkcjonalności. Po stworzeniu nowego projektu należy przejść do pliku layout'u *.xml, aby dodać w nim przycisk. Posłuży on nam jako wyzwalacz powiadomienia. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <Button android:id="@+id/btncreatenotification" android:layout_width="match_parent" android:layout_height="match_parent" android:text="create Notification" > </Button> </LinearLayout> Następnie w kodzie aktywności głównej MainActivity, należy zaimplementować tworzenie powiadomienia. W zdarzeniu oncreate tej aktywności dodajemy obsługę przycisku tworzącego i wysyłającego notyfikację. @Override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); Button btncreatenotification = (Button) findviewbyid(r.id.btncreatenotification); btncreatenotification.setonclicklistener(new View.OnClickListener() { ); @Override public void onclick(view v) { createnotification(); W dalszej kolejności należy napisać brakującą metodę wywoływaną zdarzeniem onclick powyższego przycisku. private void createnotification() { Bitmap icon = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);.setContentText("Temat wiadomości").setsmallicon(android.r.drawable.ic_dialog_info).setlargeicon(icon) notificationmanager.notify(0, noti);
Zanim uruchomimy aplikację, przyjrzyjmy się utworzonej przed chwilą metodzie createnotification(). Praca została rozpoczęta od utworzenia intencji dla aktywności ResultActivity, której uruchomienie będzie reakcją na otrzymane powiadomienie. Następnie umieściliśmy tą intencję w intencję oczekującą. W takiej postaci zostanie przekazana obiektowi notyfikacji. Dalej stworzyliśmy bitmapę, która będzie naszą dużą ikoną powiadomienia. Bitmap icon = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher); Następnie przechodzimy do tworzenia obiektu powiadomienia.setcontenttext("temat wiadomości").setsmallicon(android.r.drawable.ic_dialog_info).setlargeicon(icon) Przyjrzyjmy się również poszczególnym parametrom, które ustawiliśmy: setcontenttitle() tytuł wiadomości; setcontenttext() treść wiadomości; setticker() krótki tekst wyświetlany przez krótką chwilę bezpośrednio po otrzymaniu wiadomości, jeszcze przed rozwinięciem panelu powiadomień; setlargeicon() ustawienie dużej ikony; setsmallicon() ustawienie małej ikony; jeśli nie będzie ustawiona duża ikona (setlargeicon()), mała ikona będzie wyświetlana w polu dużej ikony, a pole małej ikony nie będzie wyświetlane; metoda jest obowiązkowa, bez niej wiadomość nie zostanie wysłana; setautocancel() jeśli ustawiona na true, po kliknięciu w powiadomienie zniknie ono automatycznie z listy, w przeciwnym razie pozostanie na liście, aż do ręcznego usunięcia; setcontentintent() podpięcie intencji oczekującej, której wywołanie zostanie uruchomione w wyniku kliknięcia w powiadomienie. Utworzony w ten sposób obiekt wiadomości trzeba wysłać. Wykorzystujemy w tym celu NotificationManager. notificationmanager.notify(0, noti); Pierwszy parametr metody notify(), to identyfikator powiadomienia. Jedno z jego zastosowań poznamy przy omawianiu grupowania powiadomień. Drugim parametrem jest obiekt wiadomości. W tym momencie można uruchomić aplikację i zobaczyć jej działanie w akcji. Kliknięcie w przycisk spowoduje wysłanie powiadomienia.
Najpierw, na górze ekranu urządzenia, wyświetlony zostanie krótki tekst, który został ustawiony poprzez metodę setticker(). Po rozwinięciu panelu ujrzymy nasze powiadomienie. Kliknięcie w nie spowoduje, zgodnie z oczekiwaniami, przejście do aktywność ResultActivity naszej aplikacji (pod warunkiem, że takie activity zostało przez nas dodane). Tworzenie powiadomień z rozszerzonym widokiem Dodajmy drugi przycisk, który wyzwoli notyfikację z rozszerzonym widokiem. <Button android:id="@+id/btncreatebignotification" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" android:text="create Big Notification" > </Button> W metodzie oncreate uwzględnijmy obsługę nowego przycisku: Button btncreatebignotification = (Button) findviewbyid(r.id.btncreatebignotification); btncreatebignotification.setonclicklistener(new View.OnClickListener() { @Override public void onclick(view v) { createbignotification(); ); Następnie należy stworzyć metodę createbignotification(). protected void createbignotification() { String[] msgpositions = new String[3]; msgpositions[0] = "Pozycja 1"; msgpositions[1] = "Pozycja 2"; msgpositions[2] = "Pozycja 3"; NotificationCompat.InboxStyle inboxstyle = new NotificationCompat.InboxStyle(); inboxstyle.setbigcontenttitle("pozycje wiadomości:"); for (int i=0; i < msgpositions.length; i++) { inboxstyle.addline(msgpositions[i]);.setcontenttext("temat wiadomości").setstyle(inboxstyle).setsmallicon(r.drawable.ic_launcher) notificationmanager.notify(1, noti);
Po uruchomieniu aplikacji tym razem wybieramy drugi przycisk. W efekcie otrzymamy powiadomienie z rozszerzonym widokiem. Tworzenie powiadomień zawierających akcje Kolejną funkcjonalność dodaną w wersji Jelly Bean są akcje w powiadomieniach. Zacznijmy od dodania nowej aktywność o nazwie ActionActivity, która będzie wywoływana poprzez akcję z powiadomienia. W jej pliku layoutu zmieńmy tylko wyświetlany tekst dla elementu TextView. <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="aktywność uruchomiona z akcji powiadomienia" /> Następnie dodajmy trzeci przycisk do layoutu *.xml <Button android:id="@+id/btncreateactionnotification" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" android:text="create Notification with Action" > </Button> Analogicznie jak w poprzednich przykładach w metodzie oncreate aktywności MainActivity dodajmy obsługę nowego przycisku. Button btncreateactionnotification = (Button) findviewbyid(r.id.btncreateactionnotification); btncreateactionnotification.setonclicklistener(new View.OnClickListener() { ); @Override public void onclick(view v) { createactionnotification(); Metoda createactionnotification() będzie wyglądała następująco: private void createactionnotification() { Intent actionintent = new Intent(this, ActionActivity.class); PendingIntent pendingactionintent = PendingIntent.getActivity(this,0,actionIntent, 0); String url = "tel:123456789"; Intent callintent = new Intent(Intent.ACTION_CALL, Uri.parse(url)); PendingIntent pendingcallintent = PendingIntent.getActivity(this, 0, callintent, 0);.setContentText("Temat wiadomości")
.setsmallicon(r.drawable.ic_launcher).addaction(android.r.drawable.ic_menu_call, "Call", pendingcallintent).addaction(r.drawable.ic_launcher, "Action", pendingactionintent) notificationmanager.notify(2, noti); Pamiętajmy, by dodać do manifestu uprawnienie do wykonywania połączeń telefonicznych. <uses-permission android:name="android.permission.call_phone" /> Kolejne etapy działania dodanej przed chwilą funkcjonalności przedstawiają screeny poniżej. Grupowanie powiadomień Powiadomienia pochodzące z tego samego źródła powinny być grupowane, a nie wyświetlane każde osobno. Należy unikać sytuacji takiej, jak zaprezentowana obok. W celu rozpoznania, które wiadomości powinny być połączone, Android wykorzystuje identyfikator powiadomienia. Wspomniałem o nim krótko przy okazji wysyłania powiadomień (notificationmanager.notify(0, noti);). W naszych przykładach każdy typ powiadomienia dostaje zawsze ten sam identyfikator, więc będą one automatycznie grupowane. Zobaczmy jednak, jak możemy zliczyć wszystkie połączone powiadomienia. Zachęcam również do własnych eksperymentów. Potrzebny będzie nam licznik, który dodamy jako pole klasy MainActivity: private int nummessages = 0; Dodajmy teraz implementację działania tego licznika oraz wyświetlanie go w powiadomieniu. Służy do tego metoda setnumber(). private void createnotification() { Bitmap icon = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher); int messagenumber = ++nummessages;.setcontenttext("wiadomość numer " + messagenumber).setsmallicon(android.r.drawable.ic_dialog_info).setlargeicon(icon).setnumber(messagenumber)
notificationmanager.notify(0, noti); Przetestujmy to działanie na emulatorze. Kolejne wysłania powiadomień powodują zwiększenie licznika, ale nie powodują ich rozmnożenia na liście. Zauważ, że w stylu normalnym powiadomienia wyświetlana jest ostatnia wiadomość, która nadeszła. Priorytety powiadomień Domyślnie notyfikacje wyświetlane są według czasu nadejścia, od najnowszego do najstarszego. Od wersji Jelly Bean możemy jednak nadawać priorytet naszemu powiadomieniu. Oznacza to, że możemy na przykład wymusić, by znajdowało się ono na samej górze listy lub jej dole, niezależnie od jego czasu nadejścia wiadomości. Mamy do wyboru pięć poziomów ważności dla naszego powiadomienia. MAX - Najwyższy priorytet. Stosowany jest dla pilnych powiadomień, które mogą być bardzo istotne dla użytkownika. Przydatny w sytuacji, gdy jego reakcja na otrzymaną wiadomość powinna być jak najszybsza. HIGH - Wysoki priorytet. Stosuje się go dla powiadomień, które mogą być ważne dla użytkownika, na przykład informacja o nieodebranym połączeniu lub nieprzeczytanej, a nadal ważnej wiadomości email. DEFAULT - Domyślny poziom powiadomienia. LOW -Niski poziom powiadomienia. Może mieć zastosowanie dla informacji, które nie są dla użytkownika tak pilne. MIN - Ten priorytet powinny dostać powiadomienia o znikomym znaczeniu dla użytkownika. W naszych dotychczasowych przykładach nigdzie nie ustawialiśmy priorytetów powiadomieniom, zatem wszystkie otrzymały poziom DEFAULT. Sprawdźmy więc, jak zachowują się one z taką konfiguracją. W tym celu wybierzmy najpierw pierwszy przycisk, a potem drugi. Jak można było się spodziewać, wiadomość rozszerzona jest powyżej zwykłej, ponieważ nadeszła później.
Wprowadźmy teraz drobną modyfikację w metodzie createnotification(). Dodajmy ustawienie parametru.setpriority(notification.priority_max) dla tworzonego obiektu Notification. private void createnotification() { int messagenumber = ++nummessages;.setcontenttext("wiadomość numer " + messagenumber).setsmallicon(r.drawable.ic_launcher).setnumber(messagenumber).setpriority(notification.priority_max) notificationmanager.notify(0, noti); Uruchamiamy aplikację i sprawdzamy, jak zachowają się nasze powiadomienia. Ponownie najpierw klikamy pierwszy przycisk, a po odczekaniu chwili wybieramy drugi. Tym razem to wiadomość zwykła jest wyżej niż wiadomość rozszerzona, mimo że ta pierwsza nadeszła wcześniej, co widać po czasach dostarczenia tych powiadomień. Nadaliśmy naszej zwykłej wiadomości najwyższy priorytet, zatem będzie wyświetlana wyżej niż powiadomienia o niższym priorytecie niezależnie od czasu ich nadesłania. Co z wcześniejszymi wersjami Androida? Dzięki zastosowaniu klasy NotificationCompat nie musimy się martwić o wsteczną kompatybilność. Należy jednak pamiętać, że w aplikacjach z wersją Androida niższą niż 4.1 wszystkie powiadomienia będą wyświetlane w trybie normalnym, bez możliwości ich rozszerzania. Nie będziemy mieli też dodatkowego obszaru na uzupełniające informacje notyfikacji. Nie skorzystamy także z akcji oraz z ustawiania priorytetów powiadomień. Zadanie: Należy stworzyć aplikację pozwalającą na wyświetlanie powiadomień na 3 wymienione powyżej sposoby włączając w to ustawienie akcji, grupowania oraz priorytetu. Źródła http://blog.atena.pl/android-howto-jak-wyslac-powiadomienie http://developer.android.com/guide/topics/ui/notifiers/notifications.html http://developer.android.com/design/patterns/notifications.html