0 komentarzy

BroadcastReceiver, podstawy komunikacji pomiędzy komponentami aplikacji

Sierpień 7, 2011 BroadcastReceiver Podstawowe komponenty Tutoriale

Wśród mocno rozbudowanych podstawowych komponentów systemowych (Aktywności, Usługi, Dostawcy Treści) znaleźć możemy jeden, bardzo prosty którym jest BroadcastReceiver.
Odbiorca komunikatów to komponent, którego jedynym zadaniem jest komunikacja pomiędzy wszystkimi elementami systemu. Służy on do przekazywania komunikatów zarówno wewnątrz aplikacji jak i wewnątrz całego systemu (pomiędzy różnymi aplikacjami). Oprócz tego może on również odgrywać rolę decydenta, który w związku z konkretnym komunikatem wykonuje jakąś czynność (BroadcastReceiver może m.in. uruchamiać Aktywności lub Usługi).

W aplikacjach pisanych pod system Android BroadcastReceiver najczęściej wykorzystywany jest w jednej z dwóch odmian:

  • Oddzielna klasa – tworzona przy bardziej rozbudowanych Odbiorach komunikatów. Zwykle obsługuje wiele różnych intencji, sama uruchamia odpowiednie komponenty systemowe, działa niezależnie od innych komponentów. Rejestrowana jest za pomocą pliku AndroidManifest.xml, dzięki czemu zdefiniowana jest jeszcze przed uruchomieniem całej aplikacji. Przykładem takiego samodzielnego BroadcastReceivera może być nasz snippet obsługujący przychodzące wiadomości SMS (link).
  • Podklasa (klasa zagnieżdżona) – tworzona jest wtedy, gdy chcemy naszemu komponentowi (Usłudze, Aktywności) dać możliwość odbierania komunikatów. Najczęściej tego typu Odbiorcy obsługują niewielką ilość intencji przeznaczonych dla komponentu, w którym są zagnieżdżone. Tworzenie oraz rejestracja tego typu odbiorcy najczęściej odbywa się w momencie uruchomienia komponentu, który go przechowuje. Wtedy też definiuje się wszelkie filtry intencji, na które ma reagować.

Najprostszy Odbiorca komunikatów rozszerza abstrakcyjną klasę BroadcastReceiver oraz implementuje jej metodę onReceive(…) wywoływaną w momencie otrzymania Intencji zgodnej z ustawionymi filtrami:

public class MyReceiver extends BroadcastReceiver {
	@Override
	public void onReceive(Context context, Intent intent) {
		// TODO Auto-generated method stub
	}
}

Argumentami są tu kontekst aplikacji, która rozesłała intencję oraz intencja, która w tym momencie została rozesłana. :)

Rozgłaszanie komunikatów

Zabieg wysyłania komunikatów systemowych jest niczym innym jak rozesłaniem odpowiedniej Intencji. Odbywa się to za pomocą metody sendBroadcast(Intent intent), która w przeciwieństwie do startActivity(…) lub startService(…) wysyła intencję do systemu, który następnie przekazuje ją do wszystkich „zainteresowanych” komponentów.

Przykład:

public static final String ACTION_NEW_MSG = "pl.froger.hello.broadcastreceiver.NEW_MSG";
public static final String MSG_FIELD = "message";

private void sendMessage(String msg) {
	Intent intent = new Intent();
	intent.setAction(ACTION_NEW_MSG);
	intent.putExtra(MSG_FIELD, msg);
	sendBroadcast(intent);
}

Powyższa metoda wysyła intencję o określonej akcji (na podstawie której później ją odfiltrujemy) z jakąś wiadomością.

Rejestracja i ustawianie filtrów intencji dla BroadcastReceivera

Aby BroadcastReceiver mógł odbierać komunikaty należy zarejestrować go w systemie oraz wskazać Intencje jakie powinien odbierać. Są na to dwa sposoby:

  • Dla samodzielnych odbiorców rejestracja i ustawienie filtrów odbywa się w pliku AndroidManifest.xml.
    Przykład:

    <receiver android:name=".MyReceiver">
    	<intent-filter>
    		<action android:name="pl.froger.hello.broadcastreceiver.NEW_MSG" />
    	</intent-filter>
    </receiver>

    W tym wypadku zarejestrowaliśmy MyReceiver (nazwa klasy), do którego będą przychodzić wszystkie Intencje posiadające akcję pl.froger.hello.broadcastreceiver.NEW_MSG.

     

  • Dla odbiorców zagnieżdżonych możemy to zrobić programistycznie. Odpowiednikiem powyższego kodu XML będzie:
    MyReceiver myReceiver = new MyReceiver();
    IntentFilter intentFilter = new IntentFilter(ACTION_NEW_MSG);
    registerReceiver(myReceiver, intentFilter);

    Przy czym należy pamiętać o tym by wyrejestrować BroadcastReceiver w momencie gdy już nie będziemy go potrzebowali (np. w momencie wyłączania Aktywności/Usługi). Można to zrobić za pomocą:

    unregisterReceiver(myReceiver);

Przykładowa aplikacja z zagnieżdżonym BroadcastReceiverem

Oto kod źródłowy aplikacji, w której Usługa przesyła niewielkie komunikaty do głównej Aktywności. Bardziej znaczące linijki zostały zaznaczone.

MainActivity.java

package pl.froger.hello.broadcastreceiver;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends Activity {
	public static final String ACTION_NEW_MSG = "pl.froger.hello.broadcastreceiver.NEW_MSG";
	public static final String MSG_FIELD = "message";

	private TextView tvMessage;
	private MyReceiver myReceiver;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		tvMessage = (TextView) findViewById(R.id.tvMessage);
		initService();
		initReceiver();
	}

	private void initService() {
		Intent intent = new Intent(this, MainService.class);
		startService(intent);
	}

	private void initReceiver() {
		myReceiver = new MyReceiver();
		IntentFilter filter = new IntentFilter(ACTION_NEW_MSG);
		registerReceiver(myReceiver, filter);
	}

	@Override
	protected void onDestroy() {
		finishService();
		finishReceiver();
		super.onDestroy();
	}

	private void finishService() {
		Intent intent = new Intent(this, MainService.class);
		stopService(intent);
	}

	private void finishReceiver() {
		unregisterReceiver(myReceiver);
	}

	public class MyReceiver extends BroadcastReceiver {
		@Override
		public void onReceive(Context context, Intent intent) {
			if (intent.getAction().equals(ACTION_NEW_MSG)) {
				String message = intent.getStringExtra(MSG_FIELD);
				tvMessage.setText(message);
			}
		}
	}
}

MainService.java

package pl.froger.hello.broadcastreceiver;

import java.util.Timer;
import java.util.TimerTask;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

public class MainService extends Service {
	private int counter;
	private Timer timer;
	private TimerTask timerTask = new TimerTask() {
		@Override
		public void run() {
			counter++;
			sendMessageToActivity();
		}
	};

	private void sendMessageToActivity() {
		Intent intent = new Intent(MainActivity.ACTION_NEW_MSG);
		intent.putExtra(MainActivity.MSG_FIELD, counter + ". message from Service");
		sendBroadcast(intent);
	}

	@Override
	public void onCreate() {
		super.onCreate();
		counter = 0;
		timer = new Timer();
		timer.scheduleAtFixedRate(timerTask, 0, 4000);
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		timerTask.cancel();
		timer.purge();
	}

	@Override
	public IBinder onBind(Intent arg0) {
		return null;
	}
}

Zrzut ekranu

Kompletny kod źródłowy

Cały projekt dostępny jest na naszym githubie – HelloBroadcastReceiver.

Komentarze (0) Subskrybuj

Prześlij komentarz

Zaloguj się lub skorzystaj z profilu:

[rpxlogin redirect="http://www.android4devs.pl" prompt="" style="large"]

Możesz również zostawić komentarz bez rejestracji, korzystając z poniższego formularza:

Musisz być zalogowany aby móc pisać komentarze.