1. Welcome
Introduction
Broadcasts are messages that the Android system and Android apps send when events occur that might affect the functionality of other apps or app components. For example, the Android system sends a system broadcast when the device boots up, or when headphones are connected or disconnected. If the wired headset is unplugged, you might like your media app to pause the music.
Your Android app can also broadcast events, for example when new data is downloaded that might interest some other app. Events that your app delivers are called custom broadcasts.
In general, you can use broadcasts as a messaging system across apps and outside of the normal user flow.
A broadcast is received by any app or app component that has a broadcast receiver registered for that action. BroadcastReceiver
is the base class for code that receives broadcast intents. To learn more about broadcast receivers, see the Broadcasts overview and the Intent
reference.
In this practical, you create an app that responds to a change in the charging state of the device. To do this, your app receives and responds to a system broadcast, and it also sends and receives a custom broadcast.
What you should already know
You should be able to:
- Identify key parts of the
AndroidManifest.xml
file. - Create Implicit intents.
What you'll learn
- How to subclass a
BroadcastReceiver
and implement it. - How to register for system broadcast intents.
- How to create and send custom broadcast intents.
What you'll do
- Subclass a
BroadcastReceiver
to show a toast when a broadcast is received. - Register your receiver to listen for system broadcasts.
- Send and receive a custom broadcast intent.
2. App overview
The PowerReceiver app will register a BroadcastReceiver
that displays a toast message when the device is connected or disconnected from power. The app will also send and receive a custom broadcast to display a different toast message.
3. Task 1. Set up the PowerReceiver project
1.1 Create the project
- In Android Studio, create a new Java project called PowerReceiver. Accept the default options and use the Empty Activity template.
- To create a new broadcast receiver, select the package name in the Android Project View and navigate to File > New > Other > Broadcast Receiver.
- Name the class CustomReceiver. Make sure that Java is selected as the source language, and that Exported and Enabled are selected. Exported allows your broadcast receiver to receive broadcasts from outside your app. Enabled allows the system to instantiate the receiver.
1.2 Register your receiver for system broadcasts
A system broadcast is a message that the Android system sends when a system event occurs. Each system broadcast is wrapped in an Intent
object:
- The intent's action field contains event details such as
android.intent.action.HEADSET_PLUG
, which is sent when a wired headset is connected or disconnected. - The intent can contain other data about the event in its extra field, for example a
boolean
extra indicating whether a headset is connected or disconnected.
Apps can register to receive specific broadcasts. When the system sends a broadcast, it routes the broadcast to apps that have registered to receive that particular type of broadcast.
A BroadcastReceiver
is either a static receiver or a dynamic receiver, depending on how you register it:
- To register a receiver statically, use the
<receiver>
element in yourAndroidManifest.xml
file. Static receivers are also called manifest-declared receivers. - To register a receiver dynamically, use the app context or activity context. The receiver receives broadcasts as long as the registering context is valid, meaning as long as the corresponding app or activity is running. Dynamic receivers are also called context-registered receivers.
For this app, you're interested in two system broadcasts, ACTION_POWER_CONNECTED
and ACTION_POWER_DISCONNECTED
. The Android system sends these broadcasts when the device's power is connected or disconnected.
Starting from Android 8.0 (API level 26 and higher), you can't use static receivers to receive most Android system broadcasts, with some exceptions. So for this task, you use dynamic receivers:
- (Optional) Navigate to your
AndroidManifest.xml
file. Android Studio has generated a<receiver>
element, but you don't need it, because you can't use a static receiver to listen for power-connection system broadcasts. Delete the entire<receiver>
element. - In
MainActivity.java
, create aCustomReceiver
object as a member variable and initialize it.
private CustomReceiver mReceiver = new CustomReceiver();
Create an intent filter with Intent actions
Intent filters specify the types of intents a component can receive. They are used in filtering out the intents based on Intent
values like action and category.
- In
MainActivity.java
, at the end of theonCreate()
method, create anIntentFilter
object.
IntentFilter filter = new IntentFilter();
When the system receives an Intent
as a broadcast, it searches the broadcast receivers based on the action value specified in the IntentFilter
object.
- In
MainActivity.java
, at the end ofonCreate()
, add the actionsACTION_POWER_CONNECTED
andACTION_POWER_DISCONNECTED
to theIntentFilter
object.
filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
filter.addAction(Intent.ACTION_POWER_CONNECTED);
Register and unregister the receiver
- In
MainActivity.java
, at the end ofonCreate()
, register your receiver using theMainActivity
context. Your receiver is active and able to receive broadcasts as long as yourMainActivity
is running.
// Register the receiver using the activity context.
this.registerReceiver(mReceiver, filter);
- In
MainActivity.java
, override theonDestroy()
method and unregister your receiver. To save system resources and avoid leaks, dynamic receivers must be unregistered when they are no longer needed or before the corresponding activity or app is destroyed, depending on the context used.
@Override
protected void onDestroy() {
// Unregister the receiver.
this.unregisterReceiver(mReceiver);
super.onDestroy();
}
1.3 Implement onReceive() in your BroadcastReceiver
When a broadcast receiver intercepts a broadcast that it's registered for, the Intent
is delivered to the receiver's onReceive()
method.
In CustomReceiver.java
, inside the onReceive()
method, implement the following steps:
- Delete the entire
onReceive()
method implementation, including theUnsupportedOperationException
code. - Get the
Intent
action from theintent
parameter and store it in aString
variable calledintentAction
.
@Override
public void onReceive(Context context, Intent intent) {
String intentAction = intent.getAction();
}
- Create a
switch
statement with theintentAction
string. (Before usingintentAction
, do anull
check on it.) Display a different toast message for each action your receiver is registered for.
if (intentAction != null) {
String toastMessage = "unknown intent action";
switch (intentAction) {
case Intent.ACTION_POWER_CONNECTED:
toastMessage = "Power connected!";
break;
case Intent.ACTION_POWER_DISCONNECTED:
toastMessage = "Power disconnected!";
break;
}
// Display the toast.
}
- After the
switch
statement, add code to display a toast message for a short time:
Toast.makeText(context, toastMessage, Toast.LENGTH_SHORT).show();
- Run your app. After the app is running, connect or disconnect your device's power supply. A
Toast
is displayed each time you connect or disconnect the power supply, as long as yourActivity
is running.
4. Task 2. Send and receive a custom broadcast
In addition to responding to system broadcasts, your app can send and receive custom broadcasts. Use a custom broadcast when you want your app to take an action without launching an activity, for example when you want to let other apps know that data has been downloaded to the device.
Android provides three ways for your app to send custom broadcasts:
- Normal broadcasts are asynchronous. Receivers of normal broadcasts run in an undefined order, often at the same time. To send a normal broadcast, create a broadcast intent and pass it to
sendBroadcast(Intent)
. - Local broadcasts are sent to receivers that are in the same app as the sender. To send a local broadcast, create a broadcast intent and pass it to
LocalBroadcastManager.sendBroadcast
. - Ordered broadcasts are delivered to one receiver at a time. As each receiver executes, it can propagate a result to the next receiver, or it can cancel the broadcast so that the broadcast is not passed to other receivers. To send an ordered broadcast, create a broadcast intent and pass it to
sendOrderedBroadcast(Intent, String)
.
This practical doesn't cover ordered broadcasts, but for more information about them, see Sending broadcasts.
The broadcast message is wrapped in an Intent
object. The Intent
action string must provide the app's Java package name syntax and uniquely identify the broadcast event.
For a custom broadcast, you define your own Intent
action (a unique string). You can create Intent
objects with custom actions and broadcast them yourself from your app using one of the methods above. The broadcasts are received by apps that have a BroadcastReceiver
registered for that action.
In this task, you add a button to your activity that sends a local broadcast intent. Your receiver registers the broadcast intent and displays the result in a toast message.
2.1 Define your custom broadcast action string
Both the sender and receiver of a custom broadcast must agree on a unique action string for the Intent
being broadcast. It's a common practice to create a unique action string by prepending your action name with your app's package name.
One of the simplest ways to get your app's package name is to use BuildConfig.APPLICATION_ID
, which returns the applicationId
property's value from your module-level build.gradle
file.
- Create a constant member variable in both your
MainActivity
and yourCustomReceiver
class. You'll use this variable as the broadcastIntent
action.
private static final String ACTION_CUSTOM_BROADCAST =
BuildConfig.APPLICATION_ID + ".ACTION_CUSTOM_BROADCAST";
2.2 Add a "Send Custom Broadcast" button
- In your
activity_main.xml
layout file, replace the Hello WorldTextview
with aButton
that has the following attributes:
<Button
android:id = "@+id/sendBroadcast"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Send Custom Broadcast"
android:onClick="sendCustomBroadcast"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
- Extract the string resource.
The sendCustomBroadcast()
method will be the click-event handler for the button. To create a stub for sendCustomBroadcast()
in Android Studio:
- Click the yellow highlighted
sendCustomBroadcast
method name. A red light bulb appears on the left. - Click the red light bulb and select Create ‘sendCustomBroadcast(View)' in ‘MainActivity'.
2.3 Implement sendCustomBroadcast()
Because this broadcast is meant to be used solely by your app, use LocalBroadcastManager
to manage the broadcast. LocalBroadcastManager
is a class that allows you to register for and send broadcasts that are of interest to components within your app.
By keeping broadcasts local, you ensure that your app data isn't shared with other Android apps. Local broadcasts keep your information more secure and maintain system efficiency.
In MainActivity.java
, inside the sendCustomBroadcast()
method, implement the following steps:
- Create a new
Intent
, with your custom action string as the argument.
Intent customBroadcastIntent = new Intent(ACTION_CUSTOM_BROADCAST);
- After the custom
Intent
declaration, send the broadcast using theLocalBroadcastManager
class:
LocalBroadcastManager.getInstance(this).sendBroadcast(customBroadcastIntent);
2.4 Register and unregister your custom broadcast
Registering for a local broadcast is similar to registering for a system broadcast, which you do using a dynamic receiver. For broadcasts sent using LocalBroadcastManager
, static registration in the manifest is not allowed.
If you register a broadcast receiver dynamically, you must unregister the receiver when it is no longer needed. In your app, the receiver only needs to respond to the custom broadcast when the app is running, so you can register the action in onCreate()
and unregister it in onDestroy()
.
- In
MainActivity.java
, insideonCreate()
method, get an instance ofLocalBroadcastManager
and register your receiver with the customIntent
action:
LocalBroadcastManager.getInstance(this)
.registerReceiver(mReceiver,
new IntentFilter(ACTION_CUSTOM_BROADCAST));
- In
MainActivity.java
, inside theonDestroy()
method, unregister your receiver from theLocalBroadcastManager
:
LocalBroadcastManager.getInstance(this)
.unregisterReceiver(mReceiver);
2.5 Respond to the custom broadcast
- In
CustomReceiver.java
, inside theonReceive()
method, add anothercase
statement in theswitch
block for the customIntent
action. Use"Custom Broadcast Received"
as the text for the toast message.
case ACTION_CUSTOM_BROADCAST:
toastMessage = "Custom Broadcast Received";
break;
- Extract the string resource.
- Run your app and tap the Send Custom Broadcast button to send a custom broadcast. Your receiver (
CustomReceiver
) displays a toast message.
That's it! Your app delivers a custom broadcast and is able to receive both system and custom broadcasts.
5. Solution code
Android Studio project: PowerReceiver
6. Coding challenge
Challenge: If you were developing a music-player app, your app might need to play or pause music when the user connected or disconnected a wired headset. To implement this functionality, you need a broadcast receiver that responds to wired headset events. Implement a broadcast receiver that shows a toast message when a wired headset is connected or disconnected.
Hint: You need to register for the ACTION_HEADSET_PLUG
action. Because this is a system broadcast action, you can't register for it statically. Instead, register your receiver dynamically by using the context with Context.registerReceiver()
:
IntentFilter filter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
this.registerReceiver(mReceiver, filter);
You must also unregister the receiver when you no longer need it:
unregisterReceiver(mReceiver);
7. Summary
- Broadcast receivers are fundamental components of an Android app.
- Broadcast receivers can receive broadcasts sent by the system or by apps.
- The
Intent
used in the broadcast mechanism is completely different from intents used to start activities. - To process the incoming
Intent
associated with a broadcast, you subclass theBroadcastReceiver
class and implementonReceive()
. - You can register a broadcast receiver in the Android manifest file or programmatically.
- Local broadcasts are private to your app. To register and send local broadcasts, use
LocalBroadcastManager
. Local broadcasts don't involve interprocess communication, which makes them efficient. Using local broadcasts can also protect your app against some security issues, because data stays inside your app. - To create unique
Intent
action names for broadcasts, a common practice is to prepend the action name with your package name. - If your app targets API level 26 or higher, you cannot use the manifest to declare a receiver for most implicit broadcasts. (Implicit broadcasts, which include most system broadcasts, are broadcasts that don't target your app.) A few implicit broadcasts are exceptions. However, you can use dynamic receivers to receive all broadcasts.
8. Related concept
The related concept documentation is in 7.3: Broadcasts.
9. Learn more
Android developer documentation:
10. Homework
This section lists possible homework assignments for students who are working through this codelab as part of a course led by an instructor. It's up to the instructor to do the following:
- Assign homework if required.
- Communicate to students how to submit homework assignments.
- Grade the homework assignments.
Instructors can use these suggestions as little or as much as they want, and should feel free to assign any other homework they feel is appropriate.
If you're working through this codelab on your own, feel free to use these homework assignments to test your knowledge.
Update an app
Extend the PowerReceiver app that you created in the practical.
- Send extra data to your local custom broadcast receiver. To do this, generate a random integer between 1 and 20. Add the number to the
extra
field of theIntent
before sending the local custom broadcast. - In your receiver, extract the integer data from the
Intent
. In the toast message, display the square of the random number.
Answer these questions
Question 1
What is a system broadcast?
- A message that your app sends and receives when an event of interest occurs in the app.
- A message that is sent from an app to a different component of the same app.
- A message that the Android system sends when a system event occurs.
- A message that the Android system receives when an event of interest occurs in your app.
Question 2
Which pair of methods do you use to register and unregister your broadcast receiver dynamically?
registerBroadcast()
andunRegisterBroadcast()
.registerComponentCallbacks()
andunRegisterComponentCallbacks()
.registerBroadcastReceiver()
andunRegisterBroadcastReceiver()
.registerReceiver()
andunRegisterReceiver()
.
Question 3
Which of the following are true?
- Broadcast receivers can't see or capture the intents used to start an activity.
- Using a broadcast intent, you can't find or start an activity.
- You can use a broadcast intent to start an activity.
- You can receive the intent used to start activity in your broadcast receiver.
Question 4
Which class is used to mitigate the security risks of broadcast receivers when the broadcasts are not cross-application (that is, when broadcasts are sent and received by the same app)?
SecureBroadcast
LocalBroadcastManager
OrderedBroadcast
SecureBroadcastManager
Submit your app for grading
Guidance for graders
Check that the app has the following features:
- The app generates a random integer and sends the integer as an
Intent
extra in theLocalBroadcast
. - In the receiver's
onReceive()
method, the random integer data is extracted from theIntent
, and the integer's square is displayed in a toast message.
11. Next codelab
To find the next practical codelab in the Android Developer Fundamentals (V2) course, see Codelabs for Android Developer Fundamentals (V2).
For an overview of the course, including links to the concept chapters, apps, and slides, see Android Developer Fundamentals (Version 2).