MójDroid.pl

#19 Twórz aplikacje na Androida z Mojdroid.pl – Powiadomienia (część 1)

2012-11-04
|
Damian P.

Powiadomienie to wiadomość, która może wyświetlić się w systemie poza naszą aplikacją. To ważna cecha i należy o niej pamiętać zawsze wtedy, gdy chcemy użytkownika o czymś poinformować. Niezależnie jak to zrobimy, nasza informacja może zarówno pokazać się w naszym programie jak i w innej używanej aplikacji. Same notyfikacje dzielimy na dwa typy: Toasty, czyli proste i krótkie informacje pojawiające się na dole, oraz na Notification, czyli typowe, pełno wymiarowe powiadomienia na pasku. Dziś postaram się oba te typy omówić.

Informacja: Nie radzisz sobie z kodem? Coś Ci nie wychodzi lub nie działa? Zgubiłeś się? W tym miejscu zobaczysz pełen kod aplikacji oraz zapiszesz go na dysk.

1. Powiadomienia

Kolejny raz muszę was uprzedzić o zmianach, jakie zaszły w systemie od wprowadzenia nowego API. Tym razem to Android 4.1 namieszał w dokumentacji, przez co czytając oficjalne porady możemy się pogubić w różnych wersjach. My jednak będziemy dążyli starą ścieżką tworzenia notyfikacji, nie przejmując się póki co nowymi dodatkami (bo użytkownik ich i tak nie zauważy na Androidzie 4.0 i wcześniejszych) jak powiadomienia ze zdjęciem. Niewymagane jest zatem korzystanie z dodatkowych bibliotek. Podstawowe, normalne powiadomienie wygląda mniej więcej tak jak powyżej. Możemy ustalić tytuł (i subtytuł w drugiej linii), dodać ikonę czy wyświetlić liczbę podobnych akcji. Oczywiście nadal istnieje możliwość tworzenia swoich layoutów (o tym powiem w drugiej części), tak jak ma to miejsce na przykład w odtwarzaczach muzyki. Toast natomiast to małe okienko z prostą informacją do przekazania w obecnej chwili. Niestety, od początku systemu nie zmieniło się ono ani trochę (w przeciwieństwie do normalnych powiadomień), przez co jest to jedna z bardziej denerwujących rzeczy w systemie. Dlaczego? Jak pisałem wcześniej, notyfikacja o akcji może pokazać się poza naszą aplikacją, więc informacja na przykład o braku połączenia czy błędzie z jednego programu może pojawić się w drugim, poprawnie działającym, a użytkownik nie wie skąd ta informacja pochodzi.

2. Tworzenie powiadomienia

Wymienione wyżej powiadomienia tworzymy w różnysposób, więc rozdzielę tą część na dwie mniejsze.

Tworzenie Notification

Podobnie jak przy Dialogach, tak i tutaj powiadomienia posiadają swoją podstawową klasę do obsługi zdarzeń. W tym wypadku jest to NotificationCompat, i tak jak wcześniej - nigdy nie powinniśmy korzystać z możliwości tego obiektu bezpośrednio. Od tego są specjalne subklasy jak na przykład Builder (NotificationCompat.Builder), na którym opieramy tworzenie powiadomienia. Ogólnie patrząc na oba poznane już Buildery zauważymy, że są one do siebie bardzo podobne. Zatem, aby stworzyć nowe powiadomienie typu Notification musimy skorzystać z Buildera i jego opcji. Tworzymy więc w naszym testowym programie nowe Activity, w którym będziemy testować możliwości systemu... View_Notifications:
package com.example.moja.pierwsza.aplikacja;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class View_Notifications extends Activity implements OnClickListener {

	Button notificationFull;
	Button notificationToast;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.view_notifications);

		notificationFull = (Button) findViewById(R.id.bt_view_notifications_full);
		notificationToast = (Button) findViewById(R.id.bt_view_notifications_toast);

		notificationFull.setOnClickListener(this);
		notificationToast.setOnClickListener(this);

	}

	public void onClick(View v) {

		switch (v.getId()) {
		case R.id.bt_view_notifications_full:
			
			// Normalne powiadomienie
			
			break;
		case R.id.bt_view_notifications_toast:
			
			// Toast
			
			break;
		}

	}

}
view_notifications.xml
<?xml version="1.0" encoding="utf-8"?>
<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/button_view_notifications_full"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Notification" />

    <Button
        android:id="@+id/button_view_notifications_toast"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Toast" />

</LinearLayout>
... oraz dodajemy podstawowego Buildera.
package com.example.moja.pierwsza.aplikacja;

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class View_Notifications extends Activity implements OnClickListener {

	Button notificationFull;
	Button notificationToast;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.view_notifications);

		notificationFull = (Button) findViewById(R.id.bt_view_notifications_full);
		notificationToast = (Button) findViewById(R.id.bt_view_notifications_toast);

		notificationFull.setOnClickListener(this);
		notificationToast.setOnClickListener(this);

	}

	public void onClick(View v) {

		switch (v.getId()) {
		case R.id.bt_view_notifications_full:
			
			// Normalne powiadomienie
			
			// Nasz builder
			NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);
			
			
			break;
		case R.id.bt_view_notifications_toast:
			
			// Toast
			
			break;
		}

	}

}
Kolejnym krokiem jest dodanie do powiadomienia podstawowych (wymaganych!) opcji. Są to kolejno tytuł, ikona oraz opis. Aby to zrobić, używamy kolejno metod setContentTitle(), setSmallIcon() oraz setContentText() na naszym Builderze. Korzystając z kolejnych funkcji możecie przyjrzeć się możliwościom jakie oferuje nam ten element.
package com.example.moja.pierwsza.aplikacja;

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class View_Notifications extends Activity implements OnClickListener {

	Button notificationFull;
	Button notificationToast;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.view_notifications);

		notificationFull = (Button) findViewById(R.id.bt_view_notifications_full);
		notificationToast = (Button) findViewById(R.id.bt_view_notifications_toast);

		notificationFull.setOnClickListener(this);
		notificationToast.setOnClickListener(this);

	}

	public void onClick(View v) {

		switch (v.getId()) {
		case R.id.bt_view_notifications_full:
			
			// Normalne powiadomienie
			
			// Nasz builder
			NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);
			
			// Dodajemy podstawowe (wymagane) elementy
			mBuilder.setContentTitle("Tytuł powiadomienia");
			mBuilder.setContentText("Opis powiadomienia");
			mBuilder.setSmallIcon(R.drawable.ic_launcher);
			
			
			
			break;
		case R.id.bt_view_notifications_toast:
			
			// Toast
			
			break;
		}

	}

}
Ważną częścią powiadomienia jest również akcja. Nie jest to wymagana część, ale w końcu nasza wyświetlona informacja ma do czegoś służyć. Tutaj decyzja o tym co ma się wydarzyć po wybraniu jednej z opcji należy wyłącznie do was. Na potrzeby poradnika stworzę coś prostego - po kliknięciu po prostu otworzona zostanie nasza aplikacja jeszcze raz. Jak się do tego zabrać? Bardzo prosto - tworząc nowego Intenta (z opcjami) i przypisując jego zadanie do czegoś, co nazywa się PendingIntent. Cóż to takiego? Najzwyklejszy opis, który zawiera zarówno zwykły Intent jak i dane aplikacji, która go wywołała. Dzięki temu system (lub jakiś inny program) wie co ma zrobić po otrzymaniu obiektu tego typu. Dodatkowym atutem PendingIntentu jest to, że może on posiadać prawa, na mocy których inne elementy Androida mogą dołączać się do naszego programu i korzystać z jego możliwości i zasobów. Wracając jednak do kodu naszego powiadomienia. Chcemy powtórnie otworzyć naszą aplikację, jeżeli wybrane zostanie powiadomienie. Tworzymy więc Intent ze wskazaniem na odpowiednią klasę, po czym dołączamy całość do PendingIntentu, który znowu przypisany zostanie do jednej z akcji Buildera (setContentIntent()).
package com.example.moja.pierwsza.aplikacja;

import android.app.Activity;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class View_Notifications extends Activity implements OnClickListener {

	Button notificationFull;
	Button notificationToast;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.view_notifications);

		notificationFull = (Button) findViewById(R.id.bt_view_notifications_full);
		notificationToast = (Button) findViewById(R.id.bt_view_notifications_toast);

		notificationFull.setOnClickListener(this);
		notificationToast.setOnClickListener(this);

	}

	public void onClick(View v) {

		switch (v.getId()) {
		case R.id.bt_view_notifications_full:
			
			// Normalne powiadomienie
			
			// Nasz builder
			NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);
			
			// Dodajemy podstawowe (wymagane) elementy
			mBuilder.setContentTitle("Tytuł powiadomienia");
			mBuilder.setContentText("Opis powiadomienia");
			mBuilder.setSmallIcon(R.drawable.ic_launcher);
			
			// Tworzymy intent
			Intent mIntent = new Intent(this, View_Main.class);
			PendingIntent mPendingIntent = PendingIntent.getActivity(this, 0, mIntent, 0);
			
			// I go łączymy
			mBuilder.setContentIntent(mPendingIntent);
			
			break;
		case R.id.bt_view_notifications_toast:
			
			// Toast
			
			break;
		}

	}

}
Opisaliśmy już główne części powiadomienia. Czas je wyświetlić. Jak to zrobić? Jak już nie raz dziś pisałem, nasze notyfikacje obsługiwane są przez system a nie przez nas samych. Zatem należy skorzystać z jednego z rozwiązań Androida, w tym przypadku NotificationManagera, aby mieć możliwość utworzenia powiadomienia na pasku. Czym on jest, nie trzeba tłumaczyć. Ten element po prostu dba o wyświetlanie powiadomień w odpowiednim czasie. Aby powiadomić Managera o nowo stworzonym wydarzeniu, należy skorzystać z jednej z metod - notify.
package com.example.moja.pierwsza.aplikacja;

import android.app.Activity;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class View_Notifications extends Activity implements OnClickListener {

	Button notificationFull;
	Button notificationToast;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.view_notifications);

		notificationFull = (Button) findViewById(R.id.bt_view_notifications_full);
		notificationToast = (Button) findViewById(R.id.bt_view_notifications_toast);

		notificationFull.setOnClickListener(this);
		notificationToast.setOnClickListener(this);

	}

	public void onClick(View v) {

		switch (v.getId()) {
		case R.id.bt_view_notifications_full:
			
			// Normalne powiadomienie
			
			// Nasz builder
			NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);
			
			// Dodajemy podstawowe (wymagane) elementy
			mBuilder.setContentTitle("Tytuł powiadomienia");
			mBuilder.setContentText("Opis powiadomienia");
			mBuilder.setSmallIcon(R.drawable.ic_launcher);
			
			// Tworzymy intent
			Intent mIntent = new Intent(this, View_Main.class);
			PendingIntent mPendingIntent = PendingIntent.getActivity(this, 0, mIntent, 0);
			
			// I go łączymy
			mBuilder.setContentIntent(mPendingIntent);
			
			NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
			mNotificationManager.notify(0, mBuilder.build());
			
			break;
		case R.id.bt_view_notifications_toast:
			
			// Toast
			
			
			
			break;
		}

	}

}
Po wybraniu przycisku w Activtiy utworzone zostanie nowe powiadomienie.

Tworzenie Toast

Tworzenie Toastu jest dużo prostsze, głównie dla tego, że sama notyfikacja nie jest tak skomplikowana i rozbudowana. Sam Toast posiada tylko dwie opcje do skonfigurowania - tekst, jaki ma zostać wyświetlony, oraz przedział czasowy, w jakim ma być widoczne okienko. Aby jeszcze bardziej sprawę uprościć, przedziału czasowego nie możemy zdefiniować ręcznie - musimy skorzystać z dwóch rodzajów: długo (TOAST_LONG) albo krótko (TOAST_SHORT) widoczne powiadomienie.
package com.example.moja.pierwsza.aplikacja;

import android.app.Activity;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class View_Notifications extends Activity implements OnClickListener {

	Button notificationFull;
	Button notificationToast;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.view_notifications);

		notificationFull = (Button) findViewById(R.id.bt_view_notifications_full);
		notificationToast = (Button) findViewById(R.id.bt_view_notifications_toast);

		notificationFull.setOnClickListener(this);
		notificationToast.setOnClickListener(this);

	}

	public void onClick(View v) {

		switch (v.getId()) {
		case R.id.bt_view_notifications_full:
			
			// Normalne powiadomienie
			
			// Nasz builder
			NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);
			
			// Dodajemy podstawowe (wymagane) elementy
			mBuilder.setContentTitle("Tytuł powiadomienia");
			mBuilder.setContentText("Opis powiadomienia");
			mBuilder.setSmallIcon(R.drawable.ic_launcher);
			
			// Tworzymy intent
			Intent mIntent = new Intent(this, View_Main.class);
			PendingIntent mPendingIntent = PendingIntent.getActivity(this, 0, mIntent, 0);
			
			// I go łączymy
			mBuilder.setContentIntent(mPendingIntent);
			
			NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
			mNotificationManager.notify(0, mBuilder.build());
			
			break;
		case R.id.bt_view_notifications_toast:
			
			// Toast
			
			Toast.makeText(this, "Toast!", Toast.LENGTH_SHORT).show();
			
			break;
		}

	}

}
Ot to wszystko. Niestety czasu mu nie starczy aby bardziej omówić ten temat, więc powiadomienia z własnym layoutem zostawię na jutro.