Broadcast Receivers - Android Application Development: A Beginner's Tutorial (2015)

Android Application Development: A Beginner's Tutorial (2015)

Chapter 25. 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 chapter 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 25.1 shows intent actions defined in the android.content.Intent class for which you can write a receiver.

Action

Description

ACTION_TIME_TICK

The current time has changed. Sent every minute.

ACTION_TIME_CHANGED

The time has been set.

ACTION_TIMEZONE_CHANGED

The timezone has changed.

ACTION_BOOT_COMPLETED

The system has finished booting.

ACTION_PACKAGE_ADDED

A new application package has been installed on the device.

ACTION_PACKAGE_CHANGED

An application package has been changed.

ACTION_PACKAGE_REMOVED

An application package has been removed.

ACTION_PACKAGE_RESTARTED

The user has restarted a package.

ACTION_PACKAGE_DATA_CLEARED

The user has cleared the data of a package.

ACTION_UID_REMOVED

A user UID has been removed.

ACTION_BATTERY_CHANGED

The battery’s charging state, level or other detail has changed.

ACTION_POWER_CONNECTED

External power has been connected to the device.

ACTION_POWER_DISCONNECTED

External power has been disconnected from the device.

ACTION_SHUTDOWN

The device is about to shut down

Table 25.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 ofonReceive 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 25.1

Listing 25.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 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 25.1 shows the broadcast receiver-based clock.

image

Figure 25.1: A receiver-based clock

Canceling A Notification

Chapter 3, “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 25.2.

Listing 25.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 25.3. The activity’s onCreate method instantiates a receiver whose onReceive method cancels the notification.

Listing 25.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 25.2.

image

Figure 25.2: CancelNotificationDemo

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

image

Figure 25.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.