Saturday, 30 April 2016

Android BroadcastReceiver and PendingIntent Example

Hello Guys!!! Wishing you all Doing Well !!!!
Definition
A BroadcastReceiver is an Android app component that responds to system-wide broadcast announcements. 

Explanation
Device  screen on  or  off,  Battery is getting Low or Battery start charging, Camera captured some image all this event get  broadcast by Android System.  Apart from these system broadcast, App can also broadcast there event  like SMS app broadcasting that an SMS has being received and let other apps know about this event so that they can trigger some action.
Unlike Activities broadcast receivers do not have any user interface but may create a status bar notification. It is intended to do minimal amount of work and can delegate hardcore jobs to Services.
So you can say broadcast receivers are like hidden app components that can register for various system or application events (intents). Once any of those events occur the system notifies all the registered broadcast receivers and brings them up into action which could be notifying the user or perform some other job.

Implementation
A receiver can be registered via the AndroidManifest.xml file.
Alternatively to this static registration, you can also register a receiver dynamically via the Context.registerReceiver() method.
The implementing class for a receiver extends the BroadcastReceiver class.
If the event for which the broadcast receiver has registered happens, theonReceive() method of the receiver is called by the Android system.

Type of Broadcast

  •  Global  Broadcast
  •  Local Broadcast

Local Broadcast  :-  If you don't need to send broadcasts across applications, consider using this class with LocalBroadcastManager. This will give us a much more efficient implementation (no cross-process communication needed) and allow us to avoid thinking about any security issues related to other applications being able to receive or send your broadcasts. simple example of how to use it.
// Generally in your onResume()
LocalBroadcastManager.getInstance(this).registerReceiver(new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String message = intent.getStringExtra("foo");
        Log.d("LocalBroadcastManager", "foo : " + message);
    }
}, new IntentFilter("my-custom-event"));

We saw how to register, now here’s how to send an intent to it:

// Send

Intent intent = new Intent("my-custom-event");

intent.putExtra("foo", "bar");

LocalBroadcastManager.getInstance(this).sendBroadcast(intent);


Global Broadcast  :-   Global Broadcast sent across the application( when cross-process communication needed).  Any application can receive(based on permission any if you provided, only intended app receive it)it.  

Type of Global Broadcast :-

  • Normal Broadcasts
  • Ordered Broadcasts

Normal Broadcast :-  It is sent with Context.sendBroadcast(). It is  completely asynchronous, i.e., the broadcasts events/intents are received by all the receivers in an asynchronous fashion. The receivers are run in an undefined order, often at the same time. It’s efficient but receivers cannot use results from other receivers or abort the entire chain of execution at a certain level.
Ordered Broadcast :-  It is sent with Context.sendOrderedBroadcast(). It is  delivered to one receiver at a time. The order can be controlled withandroid:priority attribute of the matching intent-filter. Receivers with same priority will be executed in a random order. As each receiver executes in order, it can transmit the result to the next one or even abort the entire broadcast chain so that no other receivers receive the broadcast intent and are executed.

Creating a BroadcastReceiver
Let’s quickly see how to implement a broadcast receiver

public class MyReceiver extends BroadcastReceiver {
    public MyReceiver() {
    }
    @Override
    public void onReceive(Context context, Intent intent) {
        // This method is called when this BroadcastReceiver receives an Intent broadcast.
        Toast.makeText(context, "Action: " + intent.getAction(), Toast.LENGTH_SHORT).show();
    }
}

Registering the Broadcast Receiver
We’re done with the creation but it needs to be registered so that it can receive events (intents). There are two ways to do this:

  • Statically in the manifest file.
  • Dynamically in the code.

Registering BroadcastReceiver in the Manifest File
<receiver android:name="com.example.androidtest.MyReceiver"android:enabled="true" android:exported="true" >
    <intent-filter>
        <action android:name="com.example.androidtest.BroadcastReceiver" />
    </intent-filter>
</receiver>
We use the <receiver> tag to register our broadcast receiver with an intent filter.Basically using intent filters we tell the system any intent that matches our criterias (subelements) should get delivered to that specific app component (a broadcast receiver in this case).

Registering BroadcastReceiver Programatically(Dynamically in the code)
IntentFilter filter = new IntentFilter("com.example.androidtest.BroadcastReceiver");
MyReceiver myReceiver = new MyReceiver();
registerReceiver(myReceiver, filter);

First we created an IntentFilter object that specifies which event/intent our receiver will listen to. In this case it’s com.example.androidtest.BroadcastReceiver which is a custom action name, could be anything but generally the java package naming convention is followed. We’ll use this action name again while sending a broadcast that will be handled by this receiver.

Then we instantiate our broadcast receiver and call Context.registerReceiver() to actually register our receiver that will be called and run in the main application thread.

It’s important to note that when we register a receiver in this way, it lives for as long as the component that does the registration lives. Once the component that had made the registerReceiver() call is destroyed sendBroadcast() will also stop working, hence the receiver won’t receive anymore be it an event generated from an app or the system. Whereas with the previous method where we registered via the manifest file, this is not the case. When registering a receiver in Activity.onResume(), it is strongly suggested to unregister them receivers in Activity.onPause() to avoid unnecessary system overhead as intents won’t be received when paused anyway.

@Overrideprotected void onPause() {
    unregisterReceiver(mReceiver);
    super.onPause();
}

Creating and Sending the Broadcast Event/Intent

We’ve seen how to create a broadcast receiver and then register it statically or dynamically. Finally we need to learn how to create a broadcast intent and send it to our receiver.

Intent intent = new Intent();

intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
intent.setAction("com.example.androidtest.BroadcastReceiver");
intent.putExtra("Foo", "Bar");
sendBroadcast(intent);


Second line where I setFLAG_INCLUDE_STOPPED_PACKAGES – that’s interesting. This flag basically means include intent
filters of stopped applications too in the list of potential targets to resolve
against. Similarly there isFLAG_EXCLUDE_STOPPED_PACKAGES that does the opposite, i.e., excluding. When neither or both of
them are specified then the default behaviour is including but in case of
broadcast receivers the system addsFLAG_EXCLUDE_STOPPED_PACKAGES to all broadcast intents by default. More on this subject here.
STOPPED STATE of an app is when it is
installed but not launched or force stopped from the application manager tool.
More on this here.

Pending Intents
PendingIntent is sort of an intent whose execution can be delayed and not executed right away using something like startActivity() or startActivityForResult(), but in the future. It’s an object which acts as a wrapper around an Intent object and passed on to another app. This way we can grant permission to the foreign application to execute the underlying Intent as if it were executed from our very own app’s process.
When an Intent is given to a foreign app that ships with Android or is a third party app, then they execute it with their own permissions. Whereas a PendingIntent can wrap that Intent which the foreign app executes with your own app’s permission.
Let’s see an example where we’ll create a PendingIntent and pass it on to an AlarmManager using which we’ll access the system’s alarm services that’ll allow us to schedule a piece of code to be run at some point in the future (in our case after 3 seconds).

// In the MainActivity.onCreate()
 int seconds = 3;
// Create an intent that will be wrapped in PendingIntent
Intent intent = new Intent(this, MyReceiver.class);
 // Create the pending intent and wrap our intent
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 1, intent, 0);
 // Get the alarm manager service and schedule it to go off after 3s
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (seconds * 1000), pendingIntent);

Toast.makeText(this, "Alarm set in " + seconds + " seconds", Toast.LENGTH_LONG).show();




3 comments:

  1. Hi. Well explained. But I still have one doubt:
    You put the unregisterReceiver within a onPause function.
    I need to detect the event of connectivity to Internet (Connection, Disconnection & Change). But where within the Main Code to unregisterReceiver after the connectivity status has been detected? If I do not unregisterReceiver, I get a leaked broadcast receiver error.

    ReplyDelete
  2. Hi,
    The Android documentation doesn't prescribe a single place to register/unregister broadcast receivers. but it mentions both onStart()/onStop() and onResume()/onPause() as possibilities.
    The biggest factor in making this decision is, when does your receiver need to be able to do its job? This will determine when to register and unregister it.

    Does the receiver need to do something about the broadcast only when the activity is in focus? If so, you can register/unregister it in onReceive()/onPause().

    Does the receiver need to do something when visible, even if it doesn't have focus (e.g. when a dialog is being shown)? If so, use onStart()/onStop() to register/unregister

    Does the receiver need to know about the broadcast even when the activity isn't visible?
    For example, does it need to remember that something has happened, so that when the activity becomes visible, it can reflect the resulting state of affairs?
    Then you need to use onCreate()/onDestroy() to register/unregister. (Note there are other ways to implement this kind of functionality.)

    Note:- 1. If you register in onStart(), don't also register them in onResume(), because that would be redundant: onResume() is never called without onStart() being called first.

    2. Also keep in mind that it's best to keep onPause() as light as possible:

    ReplyDelete
  3. Very useful information that you have shared and it is very useful to me.Thanks for sharing the information with us.

    ios app development company in chennai

    ReplyDelete

Build a Custom Kernel Module for Android

Hi Guys!!!Hope you are doing well !!!. Today I will describe how you can write a custom kernel module(Hello world) for Android and load it a...