Thursday, December 26, 2013

Sticky broadcast receivers: android tutorial

Program description:

This is a sample demo program for sticky broadcast receivers in Android.


Our program has only one activity, which contains a dynamic broadcast receiver in that activity.
Activity has 2 buttons. On clicking one button we will register dynamic receiver with action com.techpalle.STICK. On clicking other button we will send a sticky broadcast to check if it really works are not. 

To send a sticky broadcast message our application has to take permission "android.permission.BROADCAST_STICKY".

What is sticky broadcast?
The broadcast that will stick with android, and will be re-delivered or re-broadcasted to the future requests from any broadcast receivers.

To understand a sticky broadcast, consider below scenario.
We are writing a game application where if battery goes down, then we will save the user score and close the application.
In the above requirement, we will close our application and save the score only 
i. if user is currently playing the game.
ii. and batter went down.

So we have to write a broadcast receiver in our application which gets triggered for BATTERY_LOW broadcast.
In our broadcast receiver, we will save the current score of the user and display a popup saying we are closing the application as battery is going down.
But remember, if user is not playing the game, then there is no point of starting our receiver.
If we write our receiver in static way (in manifest file), then our receiver will be triggered irrespective of whether user is playing our game or not. But this not what we really want. We want our broadcast receiver has to be triggered only if user is playing our game currently and battery went down.

So, we have to use dynamic receivers in our application.

Now coming to the next scenario, assume that currently it is 10am and battery went down and system has send a broadcast to all applications saying BATTERY_LOW. But assume that at that point of time user is not playing our game, and hence our receiver will not be triggered as it is dynamic receiver.

Now what will happen if user starts our application at later point of time after 10am (let us say 10:05am). Should our dynamic receiver be triggered and show a popup to the user? 
Answer would be yes, because battery is going down since 10am. But the problem is system has already sent a broadcast at 10am, at which point of time our application was not running. So as far as our application is concerned that battery low event never happened. 

This is a kind of loop hole. To solve this problem, android introduced sticky boradcasts. On sending a sticky broadcast like BATTERY_LOW that intent will stick with android system and will be redelivered to later users(applications) who requests for similar kind of action.

In our case, at 10:05am once our application is started by user, we will request android if BATTERY_LOW happened by registering our dynamic receiver. If it has happened then android will trigger our receiver immediately.

Note: sticky broadcasts mechanism works only with dynamic receivers. For normal receivers it works just like a normal broadcast.

Note: Intent used with sticky broadcast is called as sticky intent. Because that intent will stick with android for future users


First Activity:

package com.techpalle.b15_sticky;

import android.os.Bundle;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends Activity {
 Button b1, b2;
 private BroadcastReceiver br = new BroadcastReceiver() {
  
  @Override
  public void onReceive(Context context, Intent intent) {
   // TODO Auto-generated method stub
   Toast.makeText(context, "got it..", 0).show();
  }
 };
 private IntentFilter inf;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  b1 = (Button) findViewById(R.id.button1);
  b2 = (Button) findViewById(R.id.button2);
  inf = new IntentFilter();
  inf.addAction("com.techpalle.STICK");
  
  b1.setOnClickListener(new OnClickListener() {
   @Override
   public void onClick(View v) {
    // TODO Auto-generated method stub
    Intent in = new Intent();
    in.setAction("com.techpalle.STICK");
    sendBroadcast(in);
   }
  });
  b2.setOnClickListener(new OnClickListener() {
   
   @Override
   public void onClick(View v) {
    // TODO Auto-generated method stub
    registerReceiver(br, inf);
   }
  });
 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.main, menu);
  return true;
 }

}

xml file for first activity 
File name : activity_main.xml


 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
   xmlns:tools="http://schemas.android.com/tools"  
   android:layout_width="match_parent"  
   android:layout_height="match_parent"  
   android:paddingBottom="@dimen/activity_vertical_margin"  
   android:paddingLeft="@dimen/activity_horizontal_margin"  
   android:paddingRight="@dimen/activity_horizontal_margin"  
   android:paddingTop="@dimen/activity_vertical_margin"  
   tools:context=".MainActivity" >  
   <TextView  
     android:id="@+id/textView1"  
     android:layout_width="wrap_content"  
     android:layout_height="wrap_content"  
     android:text="@string/hello_world" />  
   <Button  
     android:id="@+id/button1"  
     android:layout_width="wrap_content"  
     android:layout_height="wrap_content"  
     android:layout_below="@+id/textView1"  
     android:layout_marginTop="16dp"  
     android:text="Send" />  
   <Button  
     android:id="@+id/button2"  
     android:layout_width="wrap_content"  
     android:layout_height="wrap_content"  
     android:layout_alignLeft="@+id/button1"  
     android:layout_below="@+id/button1"  
     android:layout_marginTop="68dp"  
     android:text="Register" />  
 </RelativeLayout>  

Manifest file
File name : AndroidManifest.xml


 <?xml version="1.0" encoding="utf-8"?>  
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
   package="com.techpalle.b15_sticky"  
   android:versionCode="1"  
   android:versionName="1.0" >  
   <uses-sdk  
     android:minSdkVersion="8"  
     android:targetSdkVersion="17" />  
   <application  
     android:allowBackup="true"  
     android:icon="@drawable/ic_launcher"  
     android:label="@string/app_name"  
     android:theme="@style/AppTheme" >  
     <activity  
       android:name="com.techpalle.b15_sticky.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>  
   </application>  
 <uses-permission android:name="android.permission.BROADCAST_STICKY"/>  
 </manifest>  

Download complete code : Click to download

Android Interview questions related to Sticky broadcast receivers:
Difference between broadcast, sendorderedbroadcast, and sendstickybroadcast?
How to send battery low broadcast?
Difference between Intent, Sticky Intent, and Pending Intent?

Tags: android, sticky broadcast, receivers, sticky, dynamic receivers, sticky intent, permission, BROADCAST_STICKY.

Own a smart phone or laptop with best offers:

9 comments:

  1. Nice Article with excellent explanation.. Thank you very much!!!

    ReplyDelete
  2. Excellent explanation. Cleared doubts in broadcast receivers.
    Thank you very much.

    ReplyDelete
  3. This comment has been removed by a blog administrator.

    ReplyDelete
  4. Hi Satheesh,

    Thanks a lot for such an excellent tutorial.

    ReplyDelete
  5. Really nice explanation on SendstickyBroadcast() with game application.Great tutorial.

    ReplyDelete
  6. Really nice explanation,.Thanks a lot for such an excellent tutorial.

    ReplyDelete
  7. SendstickyBroadcast is nowhere called, As per my understanding it is an example of simple dynamic broadcast.

    ReplyDelete