Broadcast Receiver w Androidzie – co to takiego?
W dzisiejszym artykule zapoznamy się z tak zwanym BroadcastReceiverem zaimplementowanym w Anroidzie. Jest to mechanizm, który umożliwia komunikację między systemem, a komponentami naszej aplikacji. Rozwiązanie to wykorzystywane jest również, do wewnętrznej komunikacji w aplikacji oraz całym systemie (można je wykorzystać na przykład do przekazywania danych między dwoma różnymi programami). Pewnie brzmi skomplikowanie? Ale na szczęście tak nie jest, zobaczycie zresztą sami…
BroadcastReceiver – implementacja
BroadcastReceivera w aplikacji możemy zaimplementować na dwa sposoby. Jako oddzielną klasę rozszerzającą BroadcastReceiver (wcześniej rejestrując ją w manifeście), na przykład w ten sposób:
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
}
}lub jako klasę zagnieżdżoną (przykładowo umieszczając kod w metodzie):
public void someMethod() {
BroadcastReceiver myReciver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
// BroadcastReciver
}
};
}UWAGA: Klasę zagnieżdżoną z BradcastReceiver możemy zaimplementować tylko i wyłącznie w komponencie (np. aktywności).
Na czym będziemy pracować?
Ok, wiemy już jak zaimplementować BroadcastReceivera w projekcie, teraz pora przejść do jakiegoś praktycznego przykładu. Jak zwykle aby nie tracić czasu utworzymy sobie w Android Studio pusty projekt, na którym będziemy dalej pracować (tworzenie projektów opisywałem w tym artykule). Oczywiście przyda nam się również kontrolka umożliwiająca wyświetlanie tekstu (np. TextView) wstawiamy więc ją na środku głównego ekranu aplikacji.
Wersja dla leniwych jest do pobrania tutaj (projekt wykonany w Android Studio 2.2).
Problem…
Chcemy wkorzystać BroadcastRecivera do rozwiązania jakiegoś problemu, załóżmy więc, że potrzebujemy aby w naszej aplikacji wyświetlała się informacja o podpięciu telefonu do ładowarki (rozpoczęciu ładowania) i odłączeniu telefonu od źródła zasilania (zakończenie ładowania), a kiedy telefon jest podpięty do ładowarki chcemy aby program wyświetlał odpowiedni komunikat na ekranie.
Rejestracja BroadcastReceivera w manifeście
Pierwszym krokiem od jakiego zaczniemy jest rejestracja Receivera. Należy to zrobić w manifeście. Po otwarciu naszego projektu w Android Studio przechodzimy więc do pliku AndroidManifest.xml znajdującego się w katalogu manifest i otwieramy go.
Następnie wewnątrz tagu <application ...> ... </application> wstawiamy taki tekst:
<receiver android:name=".MyReceiver">
<intent-filter>
</intent-filter>
</receiver>Jak widać, zrobiłem przerwę w 4 i 5 linijce, nie bez powodu. W to miejsce wstawimy ten kod:
<action android:name="android.intent.action.ACTION_POWER_CONNECTED" /> <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
Umożliwia on nam dostęp do informacji o zdarzeniu „podłączenia ładowarki” (linijka 1) oraz „odłączenia ładowarki” (linijka 2).
Całość prezentuje się następująco:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="strefakoderapl.broadcastreceiverexample">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<receiver android:name=".MyReciver" >
<intent-filter >
<action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
</intent-filter>
</receiver>
<activity android:name="strefakoderapl.broadcastreceiverexample.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>W 12 linijce powyższego kodu IDE w którym pracujemy powinno poinformować nas o błędzie. Chodzi między innymi o to, że odwołujemy się tutaj do klasy MyReciver, która nie istnieje.
Tworzymy więc odpowiednią klasę w projekcie:
import android.content.BroadcastReceiver;
public class MyReciver extends BroadcastReceiver {
}
i implementujemy metodę onReceive():
public class MyReciver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
}
}Obsługa zdarzeń przez BroadcastReceivera
W metodzie onReceive() zrobimy obsługę naszych zdarzeń. Chcemy aby na ekranie wyświetlał się komunikat informujący nas o tym, że podłączyliśmy telefon do ładowarki. Korzystamy więc z obiektu intent (który otrzymujemy jako argument) i wywołujemy na nim metodę getActions(), kolejnym elementem jest sprawdzenie czy jest to zdarzenie, które chcemy obsłużyć czyli android.intent.action.ACTION_POWER_CONNECTED (podłączenie telefonu do źródła zasilania), robimy to za pomocą wbudowanej w Jave metody equals():
@Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals("android.intent.action.ACTION_POWER_CONNECTED")) {
//obsługa zdarzenia podpięcia telefonu do ładowarki
}
}Ok, teraz pozostało nam tylko wyświetlić odpowiedni komunikat:
public class MyReciver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals("android.intent.action.ACTION_POWER_CONNECTED"))
Toast.makeText(context, "Telefon został podłączony do ładowarki", Toast.LENGTH_LONG).show();
}
}Nasz program już praktycznie działa. Możemy teraz uruchomić aplikację na telefonie, włączyć ją i podłączyć telefon do ładowarki, a otrzymamy stosowną informację o tym wydarzeniu.
UWAGA: Kiedy zamkniemy aplikację (ale dalej będzie ona zainstalowana w systemie) i podłączymy telefon do źródła zasilania, również zostaniemy o tym poinformowani odpowiednim komunikatem.
UWAGA: BroadcastReceiver zarejestrowany w Manifeście działa niezależnie od tego, czy aplikacja jest uruchomiona czy nie.
Analogicznie dodajemy obsługę zdarzenia informującego o odłączeniu ładowarki:
@Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals("android.intent.action.ACTION_POWER_CONNECTED"))
Toast.makeText(context, "Telefon został podłączony do ładowarki", Toast.LENGTH_LONG).show();
if(intent.getAction().equals("android.intent.action.ACTION_POWER_DISCONNECTED"))
Toast.makeText(context, "Telefon został odłączony od ładowarki", Toast.LENGTH_LONG).show();
}MyReciver, który stworzyliśmy wyświetla tylko komunikaty informujące o podłączeniu ładowarki bądź jej odłączeniu. Nie możemy za jego pomocą wyświetlić w aplikacji stałej informacji mówiącej o tym, że telefon jest właśnie w trakcie ładowania. Dzieje się tak dla tego, że BroadcastReceiver został zarejestrowany w manifeście, a więc będzie działał nawet jak nasz program jest obecnie wyłączony. Gdybyśmy teraz chcieli w jakiejś kontrolce z MainActivity wyświetlić tekst doszło by do błędu.
BroadcastReceiver w Aktywności
Naszym celem jest jednak wyświetlanie stałej informacji o tym, że telefon jest w trakcie ładowania. Aby to zrobić musimy skorzystać z drugiej implementacji BroadcastReceivera czyli zarejestrować go w Aktywności. Wtedy taki BroadcastReceiver działa tylko jeżeli dana aktywność jest aktywna.
Jak to zrobić? Pierwszym krokiem będzie umieszczenie klasy zagnieżdżonej BroadcastReceiver w metodzie onCreate wybranej aktywności (zgodnie z przykładem na początku artykułu):
BroadcastReceiver myReceiver1 = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
//obsługa zdarzeń podpięcia telefonu do ładowarki bądź odłączenia telefonu od ładowarki
}
};Aby nasz BroadcastReceiver był obsługiwany musimy go zarejestrować oraz „poinformować” system, jakie zdarzenie ma obsługiwać:
registerReceiver(myReceiver1, new IntentFilter(Intent.ACTION_POWER_CONNECTED));
Jak widać, użyliśmy do tego metody registerReceiver() gdzie jako pierwszy argument podaliśmy obiekt reprezentujący nasz BroadcastReceiver, a jako drugi argument podaliśmy obiekt IntentFilter z informacją, że zdarzenie które chcemy obsłużyć to ACTION_POWER_CONNECTED (podłączenie telefonu do ładowarki).
Pozostało tylko dopisać obsługę komunikatu:
final TextView textView = (TextView) findViewById(R.id.textView);
BroadcastReceiver myReceiver1 = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
textView.setText("Telefon jest w trakcie ładowania...");
}
};UWAGA: Obiekt textView używamy teraz w innej klasie, aby więc wszystko działało przy jego inicjalizacji musimy dopisać słowo kluczowe final.
Analogicznie robimy drugiego BroadcastReceivera obsługującego zdarzenie odłączenia ładowarki:
BroadcastReceiver myReceiver2 = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
textView.setText("Telefon nie jest podłączony do ładowarki...");
}
};
registerReceiver(myReceiver2, new IntentFilter(Intent.ACTION_POWER_DISCONNECTED));Cały kod metody onCreate():
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(strefakoderapl.broadcastreceiverexample.R.layout.activity_main);
final TextView textView = (TextView) findViewById(R.id.textView);
BroadcastReceiver myReceiver1 = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
textView.setText("Telefon jest w trakcie ładowania...");
}
};
BroadcastReceiver myReceiver2 = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
textView.setText("Telefon nie jest podłączony do ładowarki...");
}
};
registerReceiver(myReceiver1, new IntentFilter(Intent.ACTION_POWER_CONNECTED));
registerReceiver(myReceiver2, new IntentFilter(Intent.ACTION_POWER_DISCONNECTED));
}Nasz program jest już gotowy możemy go uruchomić i zobaczyć jak działa.
Ukończony projekt do pobrania tutaj.

Dzięki, szybko, łatwo i przejrzyście wytłumaczone.
Super opisne, ale jak zrobić aby w textView wyświetlać status otrzymania SMS-a, czyli zamiast ACTION_POWER_CONNECTED wybrać SMS_RECEIVED???
Niestety sama podmiana akcji nie pomaga.
Super opisne, ale jak zrobić aby w textView wyświetlać status otrzymania SMS-a, czyli zamiast ACTION_POWER_CONNECTED wybrać SMS_RECEIVED???