What is Broadcast Receiver?
Broadcast Receivers simply respond to broadcast events from other apps or from the Android operating system. These events, like, phone booting, low battery, charger connected, are sometime called intents. For example, applications can also initiate broadcasts to let other applications know that some data has been downloaded to the device and is available for them to use, so this is broadcast receiver who will intercept this communication and will initiate appropriate
NOTE: In this example, for binding the Views from XML resources we use ButterKnife library by Jake Wharton.
1 2 |
compile 'com.jakewharton:butterknife:8.8.1' annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1' |
just put this code in build.gradle file in your app folder and sync it.
NOTE: This example is build like any other android application, which mean that every thing goes in a right place, like no hard-coded strings, they are put in string.xml resources, color.xml, layout resources and getting them from there.
Here is the link for the whole project.
https://www.dropbox.com/s/f7zis5eii0yvi3x/BroadcastReceiverExample.lnk?dl=0
This example is separated in three parts.
Part one:
Simple Broadcast Receiver example.
In this example we will cover the basics of this android component. Our app can be set to receive some message from the system or other app. In this example our app will hear if charger is connected.
After we create our Main or Home Activity whatever suits you most, we will create new class MyChargingReceiver which must extends from BroadcastReceiver class, so we can have one overriden method onReceive() which have two arguments, Context, and Intent and we can do with them whatever we want.
1 2 3 4 5 6 7 |
public class MyChargingReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "Charging \nReceiver working!", Toast.LENGTH_SHORT).show(); } } |
In this simple, one-overriden-method class, we have registered our receiver(or listener, because acts like a listener) which have only one Toast message, knowing that our example will work
At this moment we dont do nothing with our HomeActivity.java because we need only to register our BroadcastReceiver to listen, in our Android Manifest. This kind of registration in the Android Manifest means that the registered MyCharginfReceiver will always listen to this specific event, even if our app is closed.
1 |
In this we register our Broadcast Receiver, declared the class name and we have done inside to tell the Android Manifest for which message(event) we want to register. In our case we register for intent.action.ACTION_POWER_CONNECTED, which means that our app will listen when power cable is connected to the phone. At this point. when we run our application, we dont need to do anything, because simple power connect will trigger a reaction that the Android system will emit some message(event),. saying, that power is connected to the android device, and then our receiver will listen for that event. After the event happens, the code in onReceive() method is executed. For some intent.actions we need to add permissions in the Android Manifest, like Intent.ACTION_BOOT_COMPLETED, which is executed after the device is booted, and permission android.permission.RECEIVE_BOOT_COMPLETED.
This simple example shows how to implement the Broadcast Receiver, but with this kind of work, the receiver will listen for the connection of the power, even if our app is not active anymore. Some times youll need Broadcast Receiver like this, but this is not the correct way for implementing it. The next part will provide knowledge how to manage for the receiver to listen only when our app is active.
Part two:
Broadcast Receiver programmatically implementation example.
In this example we will register our Broadcast Receiver to be triggered only in our application, and nowhere else. This way of doing it its more reliable and efficient, or in another word, we have full control when and how the Receiver will be executed. In this example, which is continuum from our previous chapter, will tweak the HomeActivity.java a little bit. Here is our custom created receiver class, very similar as the first one:
1 2 3 4 5 6 7 |
public class MyNotChargingReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "Charger disconnected\nBroadcast received", Toast.LENGTH_SHORT).show(); } } |
And here is the registration of our BroadcastReceiver in the Android Manifest:
1 |
And thats it. The rest of the magic is happening in HomeActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public class HomeActivity extends AppCompatActivity { private BroadcastReceiver broadcastReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_home); broadcastReceiver = new MyNotChargingReceiver(); } @Override protected void onStart() { super.onStart(); IntentFilter intentFilter = new IntentFilter("android.intent.action.ACTION_POWER_DISCONNECTED"); registerReceiver(broadcastReceiver, intentFilter); } @Override protected void onStop() { unregisterReceiver(broadcastReceiver); super.onStop(); } } |
We declare an RegisterReceiver object at the start of the HomeActivity, we initialized it in our onCreate() with our custom created MyNotChargingReceiver.java class, and after that we override onStart() and onStop() method for registering and unregistering our broadcast receiver.
In onStart() we register our receiver, so our activity will listen for some broadcast, and define what kind of message to listen. In our example listens to when the power to our device is disconnected with created intent filter object(in the previous chapter that was defined in our Android Manifest) and intent.action.ACTION_POWER_DISCONNECTED as argument. We start the receiver with registerReceiver() method, with two parameters: our broadcast receiver object and intent filter object.
In onStop() method we unregister the BoradcastReceiver so that this BroadcastReceiver will works in our application ONLY, and will be discontinued if the app is not active.
An here is our custom intent(broadcast receiver message) when we click the button, that we sent for triggering the receiver to react.
1 2 3 4 5 6 7 |
@OnClick(R.id.button) public void onClickIntentButton() { Intent intent = new Intent(); intent.setAction("my.intent.example.broadcast.receiver"); intent.addCategory(Intent.CATEGORY_DEFAULT); sendBroadcast(intent); } |
Part three:
Broadcast Receiver order of execution example
What if we have one message broadcasted and more receivers listening for that message? In which order will they will executed? Can it start one receiver, than another, than third one? Can i send something from one to another receiver?
The answer is YES. Receivers are versatile and can receive and send date from one to another if more of them are registered to listen so same or different message.
First lets create two BroadcastReceivers for testing.
The first one is OrderBroadcastReceiverOne.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public class OrderBroadcastReceiverOne extends BroadcastReceiver { private static final String TAG = OrderBroadcastReceiverOne.class.getSimpleName(); private static String BREAD_CRUMB = "Breadcrumb"; @Override public void onReceive(Context context, Intent intent) { Bundle bundle = getResultExtras(true); String trail = bundle.getString(BREAD_CRUMB); trail = (trail == null ? "Start->" + TAG : trail + "->" + TAG); bundle.putString(BREAD_CRUMB, trail); Log.i(TAG, "BroadCastReceiver 1 triggered: " + trail); Toast.makeText(context, "BroadCastReceiver \nONE\ntriggered", Toast.LENGTH_SHORT).show(); } } |
And the second one, OrderBroadcastReceiverTwo.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public class OrderBroadcastReceiverTwo extends BroadcastReceiver { private static final String TAG = OrderBroadcastReceiverOne.class.getSimpleName(); private static String BREAD_CRUMB = "Breadcrumb"; @Override public void onReceive(Context context, Intent intent) { Bundle bundle = getResultExtras(true); String trail = bundle.getString(BREAD_CRUMB); trail = (trail == null ? "Start->" + TAG : trail + "->" + TAG); bundle.putString(BREAD_CRUMB, trail); Log.i(TAG, "BroadCastReceiver 2 triggered: " + trail); Toast.makeText(context, "BroadCastReceiver \nTWO\ntriggered", Toast.LENGTH_SHORT).show(); } } |
Here we have simple Toast messages again to show that the receiver is working. If execute the app we will get toast “BroadCastReceiver ONE triggered” and “BroadCastReceiver TWO triggered” after that. Why is this the case? Because of the order registered in the Android Manifest. A little hint: look at both permissions in the Android Manifest. Are they different in the names? No, they are the same, and thats why receivers are both triggered. This is how you register different Receivers to listen to single message, but in our case intent because with the click of our button we sent intent, the receivers listens, they are triggered and code is executed. Below is the intent sent when we click the button:
1 2 3 4 5 6 7 |
@OnClick(R.id.buttonTwo) public void onClickButtonTwo() { Intent intent = new Intent(); intent.setAction("my.order.one.example.broadcast.receiver"); intent.addCategory(Intent.CATEGORY_DEFAULT); sendBroadcast(intent); } |
If we change places of the registered receivers, than the receivers will be triggered in that order, first receiver TWO will be executed, and then receiver ONE will be executed.
1 |
There is another case of setting the order of execution of our receivers. It can be done with command within tag, android:priority=”some int number”, and the greater the value of the number, the higher priority of execution will be.
1 |
The second registered receiver will execute, because it have higher value priority number, or in our case is number 2 which is greater than the first receiver priority number which is 1.
Here is the LogCat message:
1 2 |
10-31 13:24:16.873 23257-23257/com.xtrid.broadcastreceiverexample I/OrderBroadcastReceiverTwo: BroadCastReceiver2 triggered: Start->OrderBroadcastReceiverTwo 10-31 13:24:16.893 23257-23257/com.xtrid.broadcastreceiverexample I/OrderBroadcastReceiverOne: BroadCastReceiver1 triggered: Start->OrderBroadcastReceiverOne |
But the receivers are triggered separably, only the order is changed.
Part four:
Broadcast Receiver calling another receiver example
Finally we need to do a receiver to receiver to activity loop. When we push the button the receiver ONE will trigger, after that, receiver TWO will trigger, but only when receiver ONE have send order for receiver TWO to execute
Here is the third button for the job:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
@OnClick(R.id.buttonThree) public void onClickButtonThree() { Intent intent = new Intent(); intent.setAction("my.order.one.example.broadcast.receiver"); intent.addCategory(Intent.CATEGORY_DEFAULT); sendOrderedBroadcast(intent, null, new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Bundle bundle = getResultExtras(true); String breadcrumb = bundle.getString(BREAD_CRUMB); breadcrumb = breadcrumb + "->" + TAG; Log.i(TAG, "On Receive: " + breadcrumb); } }, null, HomeActivity.RESULT_OK, null, null); } |
The LogCat for what is happening in the background:
1 2 3 |
10-31 15:00:25.381 17663-17663/com.xtrid.broadcastreceiverexample I/OrderBroadcastReceiverTwo: BroadCastReceiver2 triggered: Start->OrderBroadcastReceiverTwo 10-31 15:00:25.401 17663-17663/com.xtrid.broadcastreceiverexample I/OrderBroadcastReceiverOne: BroadCastReceiver1 triggered: Start->OrderBroadcastReceiverTwo->OrderBroadcastReceiverOne 10-31 15:00:25.461 17663-17663/com.xtrid.broadcastreceiverexample I/HomeActivity: On Receive: Start->OrderBroadcastReceiverTwo->OrderBroadcastReceiverOne->HomeActivity |
At the end here is the less important, but needed part activity_layout.xml for HomeActivity.java
1 |