This practical codelab is part of Unit 3: Working in the background in the Android Developer Fundamentals (Version 2) course. You will get the most value out of this course if you work through the codelabs in sequence:
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.
You should be able to:
AndroidManifest.xml
file.BroadcastReceiver
and implement it.BroadcastReceiver
to show a toast when a broadcast is received.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.
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:
android.intent.action.HEADSET_PLUG
, which is sent when a wired headset is connected or disconnected.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:
<receiver>
element in your AndroidManifest.xml
file. Static receivers are also called manifest-declared 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:
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.MainActivity.java
, create a CustomReceiver
object as a member variable and initialize it.private CustomReceiver mReceiver = new CustomReceiver();
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.
MainActivity.java
, at the end of the onCreate()
method, create an IntentFilter
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.
MainActivity.java
, at the end of onCreate()
, add the actions ACTION_POWER_CONNECTED
and ACTION_POWER_DISCONNECTED
to the IntentFilter
object.filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
filter.addAction(Intent.ACTION_POWER_CONNECTED);
MainActivity.java
, at the end of onCreate()
, register your receiver using the MainActivity
context. Your receiver is active and able to receive broadcasts as long as your MainActivity
is running.// Register the receiver using the activity context.
this.registerReceiver(mReceiver, filter);
MainActivity.java
, override the onDestroy()
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();
}
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:
onReceive()
method implementation, including the UnsupportedOperationException
code.Intent
action from the intent
parameter and store it in a String
variable called intentAction
.@Override
public void onReceive(Context context, Intent intent) {
String intentAction = intent.getAction();
}
switch
statement with the intentAction
string. (Before using intentAction
, do a null
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.
}
switch
statement, add code to display a toast message for a short time: Toast.makeText(context, toastMessage, Toast.LENGTH_SHORT).show();
Toast
is displayed each time you connect or disconnect the power supply, as long as your Activity
is running.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:
sendBroadcast(Intent)
. LocalBroadcastManager.sendBroadcast
.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.
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.
MainActivity
and your CustomReceiver
class. You'll use this variable as the broadcast Intent
action.private static final String ACTION_CUSTOM_BROADCAST =
BuildConfig.APPLICATION_ID + ".ACTION_CUSTOM_BROADCAST";
activity_main.xml
layout file, replace the Hello World Textview
with a Button
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" />
The sendCustomBroadcast()
method will be the click-event handler for the button. To create a stub for sendCustomBroadcast()
in Android Studio:
sendCustomBroadcast
method name. A red light bulb appears on the left.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:
Intent
, with your custom action string as the argument.Intent customBroadcastIntent = new Intent(ACTION_CUSTOM_BROADCAST);
Intent
declaration, send the broadcast using the LocalBroadcastManager
class:LocalBroadcastManager.getInstance(this).sendBroadcast(customBroadcastIntent);
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()
.
MainActivity.java
, inside onCreate()
method, get an instance of LocalBroadcastManager
and register your receiver with the custom Intent
action:LocalBroadcastManager.getInstance(this)
.registerReceiver(mReceiver,
new IntentFilter(ACTION_CUSTOM_BROADCAST));
MainActivity.java
, inside the onDestroy()
method, unregister your receiver from the LocalBroadcastManager
:LocalBroadcastManager.getInstance(this)
.unregisterReceiver(mReceiver);
CustomReceiver.java
, inside the onReceive()
method, add another case
statement in the switch
block for the custom Intent
action. Use "Custom Broadcast Received"
as the text for the toast message.case ACTION_CUSTOM_BROADCAST:
toastMessage = "Custom Broadcast Received";
break;
CustomReceiver
) displays a toast message. That's it! Your app delivers a custom broadcast and is able to receive both system and custom broadcasts.
Android Studio project: PowerReceiver
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);
Intent
used in the broadcast mechanism is completely different from intents used to start activities.Intent
associated with a broadcast, you subclass the BroadcastReceiver
class and implement onReceive()
.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.Intent
action names for broadcasts, a common practice is to prepend the action name with your package name.The related concept documentation is in 7.3: Broadcasts.
Android developer documentation:
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:
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.
Extend the PowerReceiver app that you created in the practical.
extra
field of the Intent
before sending the local custom broadcast. Intent
. In the toast message, display the square of the random number.What is a system broadcast?
Which pair of methods do you use to register and unregister your broadcast receiver dynamically?
registerBroadcast()
and unRegisterBroadcast()
.registerComponentCallbacks()
and unRegisterComponentCallbacks()
.registerBroadcastReceiver()
and unRegisterBroadcastReceiver()
.registerReceiver()
and unRegisterReceiver()
.Which of the following are true?
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
Check that the app has the following features:
Intent
extra in the LocalBroadcast
. onReceive()
method, the random integer data is extracted from the Intent
, and the integer's square is displayed in a toast message.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).