Showing posts with label BroadcastReceiver. Show all posts
Showing posts with label BroadcastReceiver. Show all posts

Wednesday, March 28, 2012

Is starting a thread in broadcast receiver a good idea in Android?


Usually, the purpose of using thread is to perform a heavy task in the background without interrupting any UI activity. In addition, the onReceive() is running on UI thread so any long time operation may cause ANR (application not responding). Thus, most developers may think of using a thread in the onReceive() to perform long time operation to avoid the ANR issue. However, using a thread in onReceive() may not be a good idea neither.
As we already know that the broadcast receiver life cycle is very short, and it is destroyed shortly after onReceive() end. Thus, putting a thread in onReceive() will cause it to be in a state that not belong to anything and it may be easily killed which end up cause unexpected behavior. A better way to handle long time operation in onReceive() is to start an Intent Service instead (NOT bind service). See an example below on how to start a service from onReceive().
public class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        // start an intent service
        context.startService(new Intent(this, MyService.class));
    }
}
public class MyService extends Service {
    @Override
    public void onCreate() {
        super.onCreate();
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // do something here
        return START_STICKY;
    }
}

Monday, March 19, 2012

How to handle Screen Lock & UnLock in Android ?


First, unlike other broad casted intents, for Intent.ACTION_SCREEN_OFF and Intent.ACTION_SCREEN_ON you CANNOT declare them in your Android Manifest! I’m not sure exactly why, but they must be registered in an IntentFilter in your JAVA code. And so, for this example we are going to have a receiver called ScreenReceiver, and I’m going to walk you through the differences between implementing it in a Service vs. in an Activity.

In Android, we will receive the broadcasted intents for screen lock & unlock. So inonCreate() method we have to set necessary action listeners. Also declare the necessary variables in the corresponding class.

//Declare the necessary variables
private BroadcastReceiver mReceiver;

//add the  below lines of code in to your onCreate() method,
//soon after calling super method.[i.e super.onCreate()]

IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);

filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_USER_PRESENT);

// Customized BroadcastReceiver class
//Will be defined soon..

mReceiver = new ScreenReceiver();
registerReceiver(mReceiver, filter);



FYI: We will receive Intent.ACTION_SCREEN_ON  action as soon screen is on. i.e It does not mean user has unlocked the screen.

Once we have set the actions which have to be listen to, we now have to define what should happen up on receiving corresponding action-intents. To  handle receivers we define a class which inherits BroadcastReceiver class.

public class ScreenReceiver extends BroadcastReceiver {

      @Override
      public void onReceive(Context context, Intent intent)
{
            if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF))
            {    
                  Log.v("$$$$$$", "In Method:  ACTION_SCREEN_OFF");
                  // onPause() will be called.
            }
            else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON))
            {
                  Log.v("$$$$$$", "In Method:  ACTION_SCREEN_ON");
//onResume() will be called.

//Better check for whether the screen was already locked
// if locked, do not take any resuming action in onResume()

                  //Suggest you, not to take any resuming action here.       
            }
            else if(intent.getAction().equals(Intent.ACTION_USER_PRESENT))
            {
                  Log.v("$$$$$$", "In Method:  ACTION_USER_PRESENT");
//Handle resuming events
}

      }


Finally,  we have to unregister the action-intents         which ever we have set in onCreate() method. This should be done in onDestroy() of your Activity.

      @Override
      public void onDestroy()
      {
            super.onDestroy();
            Log.v("$$$$$$", "In Method: onDestroy()");
           
            if (mReceiver != null)
            {
                  unregisterReceiver(mReceiver);
                  mReceiver = null;
            }          
         
}

         One more important issue when screen locked is: our current Activity may be stopped forcefully by the system if it finds shortage of memory, instead of moving Activity to background. In such a case, we should have to save (all the necessary data) the current state of the Activity.

         In order to handle this, system will search for onSaveInstanceState() an overridden method before forcefully finishing the current Activity, and during the time of restore, it will call onRestoreInstanceState().


@Override
public void  onSaveInstanceState(Bundle outState)
{
      Log.v("$````$", "In Method: onSaveInstanceState()");
      //if necessary,set a flag to check whether we have to restore or not
      //handle necessary savings…
}

@Override
public void onRestoreInstanceState(Bundle inState)
{
      Log.v("$````$", "In Method: onRestoreInstanceState()");
      //if any saved state, restore from it…
}

That’s it. Happy coding

Saturday, February 11, 2012

How to listen for Connectivity change in android?


This is a class I wrote for myself. It listens for connectivity changes and can launch callbacks when the internet connection goes up or down.
To use it, create a new instance in your onCreate, call bind(this) in onResume and unbind(this) in onPause.
You can then do two things: call hasConnection() at any time to check if there is an Internet connection or implementOnNetworkAvailableListener in order to get notified when the network state changes.
You'll need the following permissions:
  • android.permission.INTERNET
  • android.permission.ACCESS_NETWORK_STATE

public class ConnectivityReceiver extends BroadcastReceiver {
    
    public static interface OnNetworkAvailableListener {
        public void onNetworkAvailable();
        public void onNetworkUnavailable();
    }
    
    private final ConnectivityManager connectivityManager;
    private OnNetworkAvailableListener onNetworkAvailableListener;
    private boolean connection = false;
    
    public ConnectivityReceiver(Context context) {
        connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        checkConnectionOnDemand();
    }
    
    public void bind(Context context) {
        IntentFilter filter = new IntentFilter();
        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        context.registerReceiver(this, filter);
        checkConnectionOnDemand();
    }
    
    public void unbind(Context context) {
        context.unregisterReceiver(this);
    }

    private void checkConnectionOnDemand() {
        final NetworkInfo info = connectivityManager.getActiveNetworkInfo();
        if (info == null || info.getState() != State.CONNECTED) {
            if (connection == true) {
                connection = false;
                if (onNetworkAvailableListener != null) onNetworkAvailableListener.onNetworkUnavailable();
            }
        }
        else {
            if (connection == false) {
                connection = true;
                if (onNetworkAvailableListener != null) onNetworkAvailableListener.onNetworkAvailable();
            }
        }
    }
    
    @Override
    public void onReceive(Context context, Intent intent) {
        if (connection == true && intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false)) {
            connection = false;
            if (onNetworkAvailableListener != null) {
                onNetworkAvailableListener.onNetworkUnavailable();
            }
        }
        else if (connection == false && !intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false)) {
            connection = true;
            if (onNetworkAvailableListener != null) {
                onNetworkAvailableListener.onNetworkAvailable();
            }
        }
    }
    
    public boolean hasConnection() {
        return connection;
    }
    
    public void setOnNetworkAvailableListener(OnNetworkAvailableListener listener) {
        this.onNetworkAvailableListener = listener;
    }

}

How to set up a BroadcastReceiver intent in Android?


This code will send a Broadcast with a message, from a service to an activity.
It is important to remember to register the reciever, so the Broadcast is picked up.
public class service {
//This code will send the broadcast
public static final String DB_INTENT = "com.infosol.infoburst.LogViewer.broadcast.DB_UPDATE";

private void SendBroadcast(Boolean result, String Msg){
Intent i = new Intent();
i.setAction(DB_INTENT);
i.putExtra("result", result);
i.putExtra("message", Msg);
this.sendBroadcast(i);
}
}


public class activity{

//This needs to be in the activity that will end up receiving the broadcast
registerReceiver(receiver, new IntentFilter("com.infosol.infoburst.LogViewer.broadcast.DB_UPDATE"));

//This will handle the broadcast
public BroadcastReceiver receiver = new BroadcastReceiver() {
//@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(LogService.DB_INTENT)) {
               }
}
};
}

Friday, January 27, 2012

Starting an Android Service at boot up



Android has a concept of Service, or a process that can sit in the background and run a task without needing to interact with the user. There’s plenty of reasons why a Service might not need to be running all the time (say an alarm clock app with no alarms scheduled), but for the most part, Services need to be started at boot. Here’s how, tested from Android 1.5 to 2.2, since no other example I could find on the Internet was complete for this ever-changing SDK.

This example ServiceStartAtBootService, is a member of the package com.example.ssab (StartServiceAtBoot): Be careful with your Service implementation, as the onStart() method is depreciated in newer versions of the SDK!
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
 
public class StartAtBootService extends Service 
{
     public IBinder onBind(Intent intent)
     {
      return null;
     }
 
     @Override
     public void onCreate() 
     {
      Log.v("StartServiceAtBoot", "StartAtBootService Created");
     }
 
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) 
     {
      Log.v("StartServiceAtBoot", "StartAtBootService -- onStartCommand()");         
 
         // We want this service to continue running until it is explicitly
         // stopped, so return sticky.
         return START_STICKY;
     }
 
     /*
      * In Android 2.0 and later, onStart() is depreciated.  Use
      * onStartCommand() instead, or compile against API Level 5 and
      * use both.
      * http://android-developers.blogspot.com/2010/02/service-api-changes-starting-with.html
      @Override
      public void onStart(Intent intent, int startId)
      {
       Log.v("StartServiceAtBoot", "StartAtBootService -- onStart()");         
      }
      */
 
     @Override
     public void onDestroy() 
     {
      Log.v("StartServiceAtBoot", "StartAtBootService Destroyed");
     }
}
Use any Service you already have instead of the above. Within application in your AndroidManifest.xml define your Service with an intent-filter:
<service android:name="StartAtBootService">
 <intent-filter>
  <action android:name="com.example.ssab.StartAtBootService">
  </action>
 </intent-filter>
</service>
Now the new part. The OS broadcasts ACTION_BOOT_COMPLETED when it has finished booting. Your app can ask to receive this notification by requesting permission in your manifest:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED">
</uses-permission>
Your app now gets the broadcast, but still needs to do something with it. This is done by subclassing the BroadcastReceiver class. As far as I know, ACTION_BOOT_COMPLETED is the only Intent broadcast to apps, but because this could change at any point (and I can all but guarantee it will), do yourself a favor and check the Intent in your onReceive() method:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
 
public class StartAtBootServiceReceiver extends BroadcastReceiver 
{
 @Override
 public void onReceive(Context context, Intent intent) 
 {
  if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
   Intent i = new Intent();
   i.setAction("com.example.ssab.StartAtBootService");
   context.startService(i);
  }
 }
}
The last thing you need to do is register your BroadcastReceiver in your manifest, within application:
<receiver android:name="StartAtBootServiceReceiver">
 <intent-filter>
  <action android:name="android.intent.action.BOOT_COMPLETED">
  </action>
  <category android:name="android.intent.category.HOME">
  </category>
 </intent-filter>
</receiver>
That should do it. If you’re using Eclipse, run your app once and then exit the emulator. Then issue emulator -avd your_avd_name to launch your emulator without uninstalling your app. An adb logcat | grep StartAtBootService should show your app starting at boot.