Android Tutorial: Broadcast Receivers

The Android system constantly broadcasts intents that occur during the running of the operating system and applications. In addition, applications can also broadcast user-defined intents. You can capitalize on these broadcasts by writing broadcast receivers in your application.

This article explains how to create broadcast receivers.

Overview

A broadcast receiver, or a receiver for short, is an application component that listens to a certain intent broadcast, similar to Java listeners that listen to events. Table 1.1 shows intent actions defined in the android.content.Intent class for which you can write a receiver. Similar article: Android Tutorial: Services

Table 1.1: Intent actions for receiving a broadcast

To create a receiver, you must extend the android.content.BroadcastReceiver class or one of its subclasses. In your class, you must provide an implementation for the onReceive method, which gets called when an intent for which the receiver is registered is broadcast. The signature of onReceive is as follows.

public abstract void onReceive (Context context, Intent intent)

You then have to register your class in the application manifest using the receiver element or programmatically by calling Context.registerReceiver().

BroadcastReceiver-based Clock

Android comes with widgets that can show time. However, you can also create your own clock widget that is based on the ACTION_TIME_TICK broadcast. Recall that this intent action is broadcast every minute, which is suitable for a clock.

The BroadcastReceiverDemo1 project features such a clock. It is a simple app that consists of a broadcast receiver and an activity. The receiver class is instantiated and registered every time the activity’s onResume method is called. It is deregistered when onPause is invoked.

The class for the main activity is given in Listing 1.1

Listing 1.1: The MainActivity class

package com.example.broadcastreceiverdemo1;
import java.util.Calendar;
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.text.format.DateFormat;
import android.util.Log;
import android.view.Menu;
import android.widget.TextView;

public class MainActivity extends Activity {

    BroadcastReceiver receiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public void onResume() {
        super.onResume();
        setTime();
        receiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                setTime();
            }
        };
        IntentFilter intentFilter = new IntentFilter(
                Intent.ACTION_TIME_TICK);
        this.registerReceiver(receiver, intentFilter);
    }

    public void onPause() {
        this.unregisterReceiver(receiver);
        super.onPause();
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    private void setTime() {
        Calendar calendar = Calendar.getInstance();
        CharSequence newTime = DateFormat.format(
                "kk:mm", calendar);
        TextView textView = (TextView) findViewById(
                R.id.textView1);
        textView.setText(newTime);
    }
}


An important part of the application is the onReceive method of the receiver:

@Override
public void onReceive(Context context, Intent intent) {
    setTime();
}

It is a very simple method with one line of code that calls the setTime method. The setTime method obtains the current time from a Calendar and updates a TextView.

Another important part of the application is the code that registers the receiver in the activity’s onResume method. To register a receiver, you need to create an IntentFilter specifying an intent action that will cause the receiver to be triggered. In this case, the intent action is ACTION_TIME_TICK.

IntentFilter intentFilter = new IntentFilter( 
        Intent.ACTION_TIME_TICK);
this.registerReceiver(receiver, intentFilter);

You then pass the receiver and the IntentFilter to register the receiver.

Figure 1.1 shows the broadcast receiver-based clock.

Figure 1.1: A receiver-based clock

Canceling A Notification

Article Android Tutorial: UI Components explains the various Android UI components including notifications. A problem lingers: Touching a notification’s action UI does not cancel the notification. One strategy to solve this issue is by sending a user-defined broadcast when the action UI is touched and writing a broadcast for that.

Recall that a notification action requires a PendingIntent and a PendingIntent can be programmed to send a broadcast. To solve the problem, create a user-defined intent action called cancel_notification and the corresponding PendingIntent:

Intent cancelIntent = new Intent("cancel_notification");
PendingIntent cancelPendingIntent =
        PendingIntent.getBroadcast(this, 100, cancelIntent, 0);

This PendingIntent can then be used to register a notification.

The CancelNotificationDemo project shows how this can be achieved. The application is made simple and consists of an activity that contains a broadcast receiver.

The layout file for the main activity is given in Listing 1.2.

Listing 1.2: The layout file for the main activity

<LinearLayout 
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="setNotification"
        android:text="Set Notification" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="clearNotification"
        android:text="Clear Notification" />
</LinearLayout>

The layout features two buttons, one for setting a notification and one for cancaling it.

The MainActivity class for the application is listed in Listing 1.3. The activity’s onCreate method instantiates a receiver whose onReceive method cancels the notification.

Listing 1.3: The MainActivity class

package com.example.cancelnotificationdemo;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;

public class MainActivity extends Activity {
    private static final String CANCEL_NOTIFICATION_ACTION
            = "cancel_notification";
    int notificationId = 1002;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        BroadcastReceiver receiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                NotificationManager notificationManager =
                        (NotificationManager) getSystemService(
                                NOTIFICATION_SERVICE);
                notificationManager.cancel(notificationId);
            }
        };
        IntentFilter filter = new IntentFilter();
        filter.addAction(CANCEL_NOTIFICATION_ACTION);
        this.registerReceiver(receiver, filter);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }


    public void setNotification(View view) {
        Intent cancelIntent = new Intent("cancel_notification");
        PendingIntent cancelPendingIntent =
                PendingIntent.getBroadcast(this, 100,
                        cancelIntent, 0);

        Notification notification  = new Notification.Builder(this)
                .setContentTitle("Stop Press")
                .setContentText(
                        "Everyone gets extra vacation week!")
                .setSmallIcon(android.R.drawable.star_on)
                .setAutoCancel(true)
                .addAction(android.R.drawable.btn_dialog,
                        "Dismiss", cancelPendingIntent)
                .build();

        NotificationManager notificationManager =
                (NotificationManager) getSystemService(
                        NOTIFICATION_SERVICE);
        notificationManager.notify(notificationId, notification);
    }

    public void clearNotification(View view) {
        NotificationManager notificationManager =
                (NotificationManager) getSystemService(
                        NOTIFICATION_SERVICE);
        notificationManager.cancel(notificationId);
    }
}


Again, note the part that register the receiver:

IntentFilter filter = new IntentFilter();
filter.addAction(CANCEL_NOTIFICATION_ACTION);
this.registerReceiver(receiver, filter);

Here, I create an IntentFilter that specifies a user-defined action (cancel_notification) and pass it along with the receiver to the registerReceiver method.

The main activity is shown in Figure 1.2.

Figure 1.2: CancelNotificationDemo

Now touch on the Set Notification button and open the notification drawer. You should see a notification like that shown in Figure 1.3.

Figure 1.3: The notification drawer

If you touch on the Dismiss button, a broadcast will be sent and received by the receiver in the activity. As a result, the notification will be canceled.

Summary

A broadcast receiver is an application component that listens to intent broadcasts. To create a receiver you must create a class that extends android.content.BroadcastReceiver and implements its onReceive method. To register a receiver, you can either add a receiver element in the application manifest or do so programmatically by calling Context.registerReceiver(). In either case, you must define an IntentFilter that specifies what intent should cause the receiver to be triggered.

Leave a Reply

Your email address will not be published.