Broadcast Receiver tutorial
Broadcast receivers in androidA broadcast receiver is a component of an Android process, along with activities, content providers, and services that responds to system-wide broadcast announcements. Many broadcasts originate from the system—for example, a broadcast announcing that the screen has turned off, the battery is low, or a picture was captured. Applications can also initiate broadcasts—for example, to let other applications know that some data has been downloaded to the device and is available for them to use. Although broadcast receivers don't display a user interface, they may create a status bar notification to alert the user when a broadcast event occurs. More commonly, though, a broadcast receiver is just a "gateway" to other components and is intended to do a very minimal amount of work. For instance, it might initiate a service to perform some work based on the event. As the name indicates, a broadcast receiver responds to a broadcast message sent by a client. The message itself is an Android broadcast intent. A broadcast intent (message) can invoke (or be responded to by) more than one receiver. A component such as an activity or a service uses the sendBroadcast() method available on the Context class to send a broadcast event. The argument to this method
A broadcast receiver is implemented as a subclass of BroadcastReceiver and each broadcast is delivered as an Intent object. These receiving components (broadcast receivers) then need to be registered in the manifest file through a receiver tag to indicate that the class is interested in responding to a certain type of broadcast intent.
. is an intent.
Receiver Lifecycle
A BroadcastReceiver object is only valid for the duration of the call to onReceive(Context, Intent). Once your code returns from this function, the system considers the object to be finished and no longer active.
Process Lifecycle
A process that is currently executing a BroadcastReceiver (that is, currently running the code in itsonReceive(Context, Intent)
method) is considered to be a foreground process and will be kept running by the system except under cases of extreme memory pressure. Once you return from onReceive(), the BroadcastReceiver is no longer active, and its hosting process is only as important as any other application components that are running in it. This is especially important because if that process was only hosting the BroadcastReceiver (a common case for applications that the user has never or not recently interacted with), then upon returning from onReceive() the system will consider its process to be empty and aggressively kill it so that resources are available for other more important processes.
A Broadcast Receiver must return from its onReceive handler within 10 seconds. as a part of Android responsiveness model.This means that for longer-running operations you will often use a
Service
in conjunction with a BroadcastReceiver to keep the containing process active for the entire time of your operation. Broadcast receivers can be registered in two ways
1. It can be registered in Android Manifest file
2. Inside an activity registered at runtime dynamically via the
Context.registerReceiver()
method. The First example SRM_BroadcastRecevierTutorial demonstrates a standalone broadcast receiver application which gets invoked on system message on wallpaper being changed .The Demonstrative project generates Notification when wallpaper in Home screen is changed ,portrays the Broadcastreceiver registered statically in Androidmanifest file,usage of Pending Intent passed with Notification.
1.Create Android project with details as listed in the table below.
Property name | Property value |
Project name | SRM_ |
Package name | in.ac.srmuniv.broadcastreceiver |
Activity name | - |
Layout xml name | - |
Create a Android project SRM_BroadcastReceiverTutorial and unselect createActivity checkbox
Figure 1 Creating the Project
packagein.ac.srmuniv.broadcastreceiver;
importandroid.app.Notification;
importandroid.app.NotificationManager;
importandroid.app.PendingIntent;
importandroid.content.BroadcastReceiver;
importandroid.content.Context;
import android.content.Intent;
importandroid.net.Uri;
import android.util.Log;
importandroid.widget.Toast;
public classWallPaperNotificationReceiver extendsBroadcastReceiver {
@Override
public voidonReceive(Context context, Intent intent) {
this.sendNotification(context, "You have changed Wallpaper");
}
private voidsendNotification(Context ctx, String message)
{
//Get the notification manager
String ns = Context.NOTIFICATION_SERVICE;
NotificationManager nm =
(NotificationManager)ctx.getSystemService(ns);
//Create Notification Object
inticon = R.drawable.ic_launcher;
CharSequence tickerText = "Hello";
longwhen = System.currentTimeMillis();
Notification notification =
newNotification(icon, tickerText, when);
//Set ContentView using setLatestEvenInfo
Intent intent = newIntent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.srmuniv.ac.in"));
PendingIntent pi = PendingIntent.getActivity(ctx, 0, intent, 0);
notification.setLatestEventInfo(ctx, "Intimation", message, pi);
//Send notification
nm.notify(1, notification);
Toast.makeText(ctx,"Hello Nawin",Toast.LENGTH_LONG).show();
}
}
xml version="1.0" encoding="utf-8"?>
<manifestxmlns:android="http://schemas.android.com/apk/res/android"
package="in.ac.srmuniv"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="15" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name">
<receiver android:name=".WallPaperNotificationReceiver">
<intent-filter>
<action android:name="android.intent.action.WALLPAPER_CHANGED"/>
</intent-filter>
</receiver>
</application>
</manifest>
Figure 2 Selecting wall Paper
5. Choose from wallpapers and set one as wallpaper
Figure 3 Setting Wallpaper
Figure 4.On selecting a wallpaper you can see a Toast message appearing and a notification appears at Notification barFigure 5. Expanding the Notification and selecting the notification message will call the browser
Figure 6 Shows when Notification clicked.Pending intent calls the browser to open the web page.
CODE EXPLANATION :
Android generates many in build messages by its System process which can be registered to be received for various actions to be performed in an application.A few are listed below.
android.intent.action.BATTERY_LOW
android.intent.action.DATA_SMSRECEIVED
android.intent.action.BOOT_COMPLETED
android.intent.action.CAMERA_BUTTON
For example the Intent action ACTION_BATTERY_LOW broadcasts a warning when the battery is low.If your application has battery consuming service of some kind you might want to listen for the Broadcast and shutdown your service until battery power is sufficient.
Pending Intent:
The PendingIntent can be handed to other applications so that they can perform the action you described on your behalf at a later time. By giving a PendingIntent to another application, you are granting it the right to perform the operation you have specified as if the other application was yourself (with the same permissions and identity).
String ns = Context.NOTIFICATION_SERVICE;
NotificationManager nm =
(NotificationManager)ctx.getSystemService(ns);
---------
Notification notification =
newNotification(icon, tickerText, when);
//Set ContentView using setLatestEvenInfo
Intent intent = newIntent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.srmuniv.ac.in"));
PendingIntent pi = PendingIntent.getActivity(ctx, 0, intent, 0);
notification.setLatestEventInfo(ctx, "Intimation", message, pi);
//Send notification
nm.notify(1, notification);
"pi" is an intent to launch when the user clicks the expanded notification.
The above application will only work with Android versions up to Gingerbread 2.3.6
An additional security feature is added to all Android versions from Android 3.1 where Android system excludes all receiver from receiving intents by default if the corresponding application has never been started by the user or if the user explicitly stopped the application via the Android menu (in → ). This makes user to be sure that only the applications he started will receive broadcast intents. This does not mean the user has to start the application again after a reboot. The Android system remembers that the user already started it. Only one start is required without a forced stop by the user.
In order to make the above application work in latest version of Android 4.x you need to add the following Modifications to the existing SRM_BroadcastReceiver project.
Add an Activity to the project SRM_BroadcastReceiver named MainActivity.java.
The above application will only work with Android versions up to Gingerbread 2.3.6
An additional security feature is added to all Android versions from Android 3.1 where Android system excludes all receiver from receiving intents by default if the corresponding application has never been started by the user or if the user explicitly stopped the application via the Android menu (in → ). This makes user to be sure that only the applications he started will receive broadcast intents. This does not mean the user has to start the application again after a reboot. The Android system remembers that the user already started it. Only one start is required without a forced stop by the user.
In order to make the above application work in latest version of Android 4.x you need to add the following Modifications to the existing SRM_BroadcastReceiver project.
Add an Activity to the project SRM_BroadcastReceiver named MainActivity.java.
packagein.ac.srmuniv.broadcastreciver;
importandroid.app.Activity;
import android.os.Bundle;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}.
Add the Layout main.xml in res/layout folder
</LinearLayout>
<?xml version="1.0"encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
</LinearLayout>
Modify Androidmanifest.xml as shown below. Figure 7 Shows the App invoked .
<?xml version="1.0"
encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="in.ac.srmuniv.broadcastreciver"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="8" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<receiver android:name=".WallPaperNotificationReceiver">
<intent-filter>
<action android:name="android.intent.action.WALLPAPER_CHANGED"/>
</intent-filter>
</receiver>
</application>
</manifest>
CODE EXPLANATION :
The application needs to be launched at least once,after that when you change the wallpaper it will call the receiver, even after reboot.
Dynamic Registration of BroadcastReceiverReceiver can be registered via the Android manifest file. You can also register and unregister a receiver at runtime via the
Context.registerReceiver()
and Context.unregisterReceiver()
methodsContext.unregisterReceiver()
method. If you forget this, the Android system reports aleaked broadcast receiver
error. For instance, if you registered a receive in onResume()
methods of your activity, you should unregister it in the onPause()
methodServices
Services are long running process which does not need UI. Services are created when manually started (via an API call) or when some activity tries connecting to the service via interprocess communication (IPC). Services will live until specifically shut down or until Android is desperate for RAM and destroys them prematurely we will explore them more in detail in subsequent tutorial
Handler
All Android application components including Activities, Services, and Broadcast Receivers start on the main application thread. As a result,time-consuming process in any component will block all other components including Services and the Visible Activity. Using background threads is vital to avoid the “Application Unresponsive”.Android system pops up dialog box for Unresponsiveness as Activities that don’t respond to an input event (such as a key press) within 5 seconds and Broadcast Receivers that don’t complete their onReceive handlers within 10 seconds.Android offers two alternatives for backgrounding your processing. The AsyncTask class lets you define an operation to be performed in the background, then provides event handlers you can use to monitor progress and post the results on the GUI thread. Alternatively, you can implement your own Threads and use the Handler class to synchronize with the GUI thread before updating the UI The most flexible means of making an Android-friendly background thread is to create an instance of a Handler subclass. You need only one Handler object per activity, and you do not need to manually register it. Merely creating the instance is sufficient to register it with the Android threading subsystem. Your background thread can communicate with the Handler, which will do all of its work on the activity’s UI thread. This is important, as UI changes, such as updating widgets,should occur only on the activity’s UI thread.You have two options for communicating with the Handler: Messages and Runnable objects.
Exercise 2 The Demonstrative project displays current time portrays Broadcast Receiver registered dynamically with in an Activity,how a Service will send message to Activity through Broadcast receiver.
1.Create Android project with details as listed in the table below.
Property name | Property value |
Project name | SRM_BroadcastReceiverTutorial2 |
Package name | in.ac.srmuniv.broadcastreceiver_two |
Activity name | ClockTimeActivity |
Layout xml name | main |
2.Create main.xml in res/layout folder for UI Design of ClockTimeActivity.Code listing is given below
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="@drawable/clockbg"
android:paddingLeft="20dp" >
<TextView
android:id="@+id/hr"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="00:"
android:textColor="#FFFFFF"
android:textSize="16pt" >
</TextView>
<TextView
android:id="@+id/mn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="00:"
android:textColor="#FFFFFF"
android:textSize="16pt" >
</TextView>
<TextView
android:id="@+id/sc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="00"
android:textColor="#FFFFFF"
android:textSize="16pt" >
</TextView>
</LinearLayout>
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/btnset"
android:layout_centerHorizontal="true"
android:layout_marginTop="10dp"
android:text="Digital Clock" >
</TextView>
</RelativeLayout>
3.Copy the code in ClockTimeActivity.java. Activity.
package in.ac.srmuniv.broadcastreceiver_two;import android.app.Activity;
importandroid.content.BroadcastReceiver;
importandroid.content.Context;
importandroid.content.Intent;
import android.content.IntentFilter;
importandroid.graphics.Typeface;
import android.os.Bundle;
import android.util.Log;
importandroid.widget.TextView;
public class ClockTimeActivity extends Activity {
private static final String TAG="BroadcastTime";
private Intent in;
private BroadcastReceiver timerec=new BroadcastReceiver(){
@Override
public void onReceive(Context c, Intent i) {
//Getting the values from intent and updating log
int h=i.getIntExtra("hrs", 0);
int m=i.getIntExtra("min", 0);
int s=i.getIntExtra("sec", 0);
Log.d(TAG, Integer.toString(h));
Log.d(TAG, Integer.toString(m));
Log.d(TAG, Integer.toString(s));
//Printing Time to Textview
TextView th=(TextView) findViewById(R.id.hr);
TextView tm=(TextView) findViewById(R.id.mn);
TextView ts=(TextView) findViewById(R.id.sc);
if(h>=10)
th.setText(Integer.toString(h)+":");
else
th.setText("0"+Integer.toString(h)+":");
if(m>=10)
tm.setText(Integer.toString(m)+":");
else
tm.setText("0"+Integer.toString(m)+":");
if(s>=10)
ts.setText(Integer.toString(s));
else
ts.setText("0"+Integer.toString(s));
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//Intent for starting the Time display service
in=new Intent(this,BroadCastTimeService.class);
startService(in);
//(BroadcastTime.BROADCAST_TIME));
//Code for opening alarm set activity
TextView txth = (TextView) findViewById(R.id.hr);
TextView txtm = (TextView) findViewById(R.id.mn);
TextView txts = (TextView) findViewById(R.id.sc);
Typeface fonth = Typeface.createFromAsset(getAssets(), "MyriadPro-Bold.otf");
txth.setTypeface(fonth);
txtm.setTypeface(fonth);
txts.setTypeface(fonth);
}
@Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
unregisterReceiver(timerec);
}
@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
registerReceiver(timerec, new IntentFilter("in.ac.srmuniv.displaytime"));
}
}
4.Add clockbg.png image to drawable folder and MyriadPro-Bold.otf font file in assets folder to have appropriate font for Digital Clock display
5.Add an BroadCastTimeService.java which extends Service following is the code listing
}
package in.ac.srmuniv.broadcastreceiver_two;
import java.util.Date;
import android.app.Service;
importandroid.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
public class BroadCastTimeService extends Service {
private static final String TAG="BroadcastTime";
static final String BROADCAST_TIME = "in.ac.srmuniv.displaytime";
public final Handler handler = new Handler();
Intent i;
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onCreate()
{
super.onCreate();
i = new Intent(BROADCAST_TIME);
}
@Override
public intonStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
handler.removeCallbacks(update);
handler.postDelayed(update, 1000);
return Service.START_NOT_STICKY;
}
private Runnable update= new Runnable(){
@Override
public void run() {
Log.d(TAG, "Updated Time");
i.putExtra("hrs", new Date().getHours());
i.putExtra("min", newDate().getMinutes());
i.putExtra("sec", newDate().getSeconds());
sendBroadcast(i);
handler.postDelayed(this, 1000);
}
};}
5.Modify the manifest file as per the code listing shown below which should include the entry for BroadCastTimeService but no registration is done for the Broadcast receiver since it is dynamically registered through coding
6.Run the application in the emulator you can see the Digital clock viewed in the ClockTimeActivity
<?xml version="1.0"encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="in.ac.srmuniv.broadcastreceiver_two"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="15"/>
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".ClockTimeActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<service android:name=".BroadCastTimeService"/>
</application>
</manifest>
6.Run the application in the emulator you can see the Digital clock viewed in the ClockTimeActivity
Figure 10 Shows the screen shot of Digital clock
CODE EXPLANATION
CODE EXPLANATION
ClockTimeActivity contains a Broadcast receiver object instantiated as anonymous inner class with onReceive(0 method overridden.onCreate(0 method in ClockTimeActivity calls the service class through the following code.
in=newIntent(this,BroadCastTimeService.class);
startService(in);
BroadCastTimeService is a Service which runs in background once started, used to generate time delay every one second through separate thread .An anonymous inner class Thread class implementing Runnable interface object update the time by fetching current system time .The time data is send through broadcast message in run() method. managed by Handler object handler.Handler object spawns thread every 1000 milliseconds(1 sec).
The onCreate method of BroadCastTimeServiceclass creates a intent to be broadcast with custom action message "in.ac.srmuniv.displaytime". onStartCommand(Intent intent, int flags, intstartId) is called after onCreate method where service is in active state .
The onCreate method of BroadCastTimeServiceclass creates a intent to be broadcast with custom action message "in.ac.srmuniv.displaytime". onStartCommand(Intent intent, int flags, intstartId) is called after onCreate method where service is in active state .
handler.removeCallbacks(update);
handler.postDelayed(update, 1000);
handler objects postDelayed method manages background thread of Runnable update object by calling it at specified interval of time in our example every 1000 seconds.
i.putExtra("hrs", newDate().getHours());
i.putExtra("min", newDate().getMinutes());
i.putExtra("sec", newDate().getSeconds());
sendBroadcast(i);
handler.postDelayed(this, 1000);
The above code in run() method adds hours, minutes and seconds of current time from Date class as extra message to the Intent created in onCreate method through putExtramethod and sendBroadcast() method broadcasts the intent.
ClockTimeActivity which has registered the receiver dynamically in onResume() method with custom Intent action "in.ac.srmuniv.displaytime",receives the broadcast message. Since the Broadcast receiver is implemented inside the Activity in onReceive method it is able to manipulate TextViews for displaying hours, minuite and seconds with the values taken from the Intent message through getExtra() method.
The service will be sending broadcast message managed by handler object every one second. The broadcast receiver in activity will be called every one second which in turn updates Time display in the Activity through its TextViews.
int h=i.getIntExtra("hrs", 0);
intm=i.getIntExtra("min", 0);
ints=i.getIntExtra("sec", 0);
//Printing Time to Textview
TextView th=(TextView) findViewById(R.id.hr);
TextView tm=(TextView) findViewById(R.id.mn);
TextView ts=(TextView) findViewById(R.id.sc);