Question

I wrote a simple Broadcast Receiver which catches incoming calls and starts activity with the caller's number:

package com.example.nrsearch;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;

public class CallReceiver extends BroadcastReceiver {
public CallReceiver() {
}

public Context context;

@Override
public void onReceive(Context context, Intent intent) {
    Log.i("CallReceiverBroadcast", "onReceive() is called. ");
    this.context = context;
    TelephonyManager teleMgr = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
    PhoneStateListener psl = new PhoneStateListener() {
        @Override
        public void onCallStateChanged(int state, String incomingNumber) {
            Log.i("CallReceiverBroadcast", "onCallStateChanged() is called. ");
            switch (state) {
            case TelephonyManager.CALL_STATE_RINGING:
                Log.i("CallReceiverBroadcast", "Incoming call caught. Caller's number is " + incomingNumber + ".");
                startNumberDisplayActivity(incomingNumber);
            }
        }
    };
    teleMgr.listen(psl, PhoneStateListener.LISTEN_CALL_STATE);
    teleMgr.listen(psl, PhoneStateListener.LISTEN_NONE);
}

public void startNumberDisplayActivity(String incomingNumber) {
    Intent i = new Intent(context, MainActivity.class);
    i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    i.putExtra("incomingNumber", incomingNumber);
    context.startActivity(i);
}
}

However, after the first incoming call I feel like my device's battery starts to drain pretty quickly. I'm afraid that some process still prevents my Broadcast Receiver from disconnecting (I mean my Broadcast Receiver may be running forever). So, is there something in my code that could cause such a behavior and does this line really stops the TelephonyManager from listening for call state changes: teleMgr.listen(psl, PhoneStateListener.LISTEN_NONE); or should I do it some other way?

EDIT: I'm almost sure that this class causes battery drain, because now I'm testing battery life with my app uninstalled and it's much lower than previous when this app was installed and broadcast receiver was called. I can't swear that this class is the cause of the drain but the battery consumption difference is clearly visible with and without this app. Could somebody look at this code and say what could cause the battety drain? Thanks in advance!

Was it helpful?

Solution

in the method

@Override 
public void onPause() {

super.onPause();
mActivity.unregisterReceiver(myReceiver);

}

You can put this other places, but that's a good one. DO your registration in onResume.

Also please read the broadcastreceiver docs, they don't work the way you seem to believe they do:

http://developer.android.com/reference/android/content/BroadcastReceiver.html

Basically the receiver lifecycle is:

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.

This has important repercussions to what you can do in an onReceive(Context, Intent) implementation: anything that requires asynchronous operation is not available, because you will need to return from the function to handle the asynchronous operation, but at that point the BroadcastReceiver is no longer active and thus the system is free to kill its process before the asynchronous operation completes.

In particular, you may not show a dialog or bind to a service from within a BroadcastReceiver. For the former, you should instead use the NotificationManager API. For the latter, you can use Context.startService() to send a command to the service.

Edit:

As per your comments - the concern about the BroadcastReceiver eating battery life isn't real. The receiver only lasts as long as it takes to run the code in it's on receiver method. At that point Android will clean it up as it deems nescesary. If anything in your code is breaking this it would be:

this.context = context;

/// these three lines
    TelephonyManager teleMgr = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
   .....
    teleMgr.listen(psl, PhoneStateListener.LISTEN_CALL_STATE);
teleMgr.listen(psl, PhoneStateListener.LISTEN_NONE);

since you create a object and then try to listen on it.

However you should really read the docs:

anything that requires asynchronous operation is not available,

Which is EXACTLY what you are doing in your code - attaching to a service and and waiting for its asyncronous response. This isn't acceptable in a BroadcastReceiver, and is clearly indicated in the docs at this point:

In particular, you may not show a dialog or bind to a service from within a BroadcastReceiver.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top