Informacje o nowych artykułach oraz akcjach edukacyjnych prosto na Twojej skrzynce e-mail!

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…

Fot: nyphotographic.com, CC BY-SA 3.0.

Fot: nyphotographic.com, CC BY-SA 3.0.

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 <applcation ...> ... </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.

Spodobało się?

Jeśli tak, to zarejestruj się do newslettera aby otrzymywać informacje nowych artykułach oraz akcjach edukacyjnych. Gwarantuję 100% satysfakcji i żadnego spamowania!

, , , , , , , , , , ,

Dodaj komentarz

Komentarze (3)

  • Bartek_Wojak pisze:

    Dzięki, szybko, łatwo i przejrzyście wytłumaczone.

  • Philogy pisze:

    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.

  • Philogy pisze:

    Super opisne, ale jak zrobić aby w textView wyświetlać status otrzymania SMS-a, czyli zamiast ACTION_POWER_CONNECTED wybrać SMS_RECEIVED???

Odpowiedz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

Pin It on Pinterest