To implement a simple sleep detection app I need to handle ACTION_SCREEN_OFF and ACTION_SCREEN_ON broadcasts in order to get the timing related to user's sleep (based on device inactivity). However, these broadcasts cannot be put in the manifest; the receiver has to be un-/registered in some app component.
How can I implement that? It seems to me that registering the receiver in, say,
a Service won't do much since after the service is done it should call for unregister. Unless I have a long, persistent service which is not doing anything.
You can create a STIKY service that is registering to a broadcast receiver.
In your broadcast check for on/off state in onReceive method:
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
// screen off
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
// screen on
}
And register like this in your service:
YourBroadcastReceived receiver = new YourBroadcastReceiver();
IntentFilter screenStateFilter = new IntentFilter();
screenStateFilter.addAction(Intent.ACTION_SCREEN_ON);
screenStateFilter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(receiver, screenStateFilter);
Don't forget to unregister after service is killed and always register just one time when service is created.
Related
I am creating widget app that sync data with server i am registering BroadCastReceiver dynamically for receiving SCREEN_ON and SCREEN_OFF broadcasts i registered my BroadCastReceiver in class that extends Application, but the problem is that if the process is running it app receive SCREEN_ON and SCREEN_OFF broadcasts but if process is died then application would not be able to get receive broadcast why? in BroadCastReceiver theory they says app will receive broadcast even if it is not running.
public class ThisApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
Utils.logCat("ThisApplication", "onCreate()");
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
intentFilter.addAction(Intent.ACTION_SCREEN_ON);
registerReceiver(new ScreenOnOffReceiver(), intentFilter);
}
}
public class ScreenOnOffReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
Utils.logCat("Screen ScreenOnOffReceiver", "SCREEN is ON");
}
else
{
Utils.logCat("Screen ScreenOnOffReceiver", "SCREEN is OFF");
}
}
}
1 - You forgot to add the context to your new ScreenOnOffReceiver()
Change it to new ScreenOnOffReceiver(this).
2 - I guess you have an onPause(); method containing unregisterReceiver()?
This makes sure that when your app closes the BroadcastReceiver gets closed or unregistered as well. So it would be better to register your receiver directly using the manifest file. If for some reason you do HAVE to register it dynamically:
Use an if statement to check if your receiver is listening. If it is don't create another one. If it is not create one. If you want to know how(the code) comment below and I will do so)
BroadcastReceiver registered in the AndroidManifest.xml will receive broadcasts even if the process is not running
BroadcastReceiver registered during runtime only exist while the VM is running and will not be called if the process dies.
That is the rule, that is the indented behavior, it is always been like that, you cannot change it.
Said that:
if you want a you can during runtime enable/disable a BroadcastReceiver that is registered in the manifest like in this answer:
Enable and disable a Broadcast Receiver
In my onresume() of activity, I have this
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(mReceiver, intentFilter);
Every time the onResume() activate, mReceiver always received a broadcast have the action of ConnectivityManager.CONNECTIVITY_ACTION
That's strange, because my networkstate is in a stable wifi and does not changed at all.
every time onresume is activited , registerReceiver is called one more each time.
registerReceiver sends bck sticky broadcasts. Sticky broadcasts are sent to receiver as soon as registerBroadcast is called.
you can use unregisterReceiver or check you will have to check whether you have already registered and skip , if yes..
As per documentation for registerReceiver (BroadcastReceiver receiver, IntentFilter filter):
The system may broadcast Intents that are "sticky" -- these stay around after the broadcast as finished, to be sent to any later registrations. If your IntentFilter matches one of these sticky Intents, that Intent will be returned by this function and sent to your receiver as if it had just been broadcast.
Though you are just registering your receiver right now but it's up to the system when to broadcast that Intent and since that intent is a sticky one so it gets broadcasted as soon as you register.
Check out this ConnectivityManager.CONNECTIVITY_ACTION, always broadcast when registering a receiver?
Seems sticky broadcasts is a common problem for action ConnectivityManager.CONNECTIVITY_ACTION,
Follow the instruction I tried to describe the receiver in XML but it seems NOT OK with that
AT last,I used a flexible method to resolve this:Since everytime in Onresume will send that broadcast,I set a boolean value to be 'false',when the onresume called the receiver for the first time,the program will do nothing but just set this boolean value to 'true'.
Then when CONNECTIVITY changed,it will go normal process.
This seems not an elegant method ,but it worked in my app.
A solution is to use isInitialStickyBroadcast in the onReceive callback of your BroadcastReceiver to know if you are actually proceeding a sticky broadcast and act accordingly (BroadcastReceiver : isInitialStickyBroadcast)
I have a dynamically registered BroadcastReceiver on a Service. It gets AudioManager.RINGER_MODE_CHANGED_ACTION as IntentFilter. Every time I start the service I get the log message in onReceive() method. It works normally after that. I do not want it to receive once when service is started each time. Could you please tell me what I am missing here?
receiver=new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent) {
Log.d("zil", "degisti");
}
};
IntentFilter filter=new IntentFilter(
AudioManager.RINGER_MODE_CHANGED_ACTION);
registerReceiver(receiver,filter);
The intent you are interested in, AudioManager.RINGER_MODE_CHANGED_ACTION, is "sticky". That means that the system always keeps the last broadcast sent and whenever a BroadcastReceiver is registered that is interested in that Intent, it receives it right away. This is a very useful feature but sometimes it isn't what you want ;-)
I assume that you are only interested in actual "change" events. In this case you need to ignore the "current" event and listen only for any events that happen in the future. Lucky for you, there is a solution:
In 'onReceive()' do the following:
if (isInitialStickyBroadcast()) {
// Ignore this one as we aren't interested in the current state
} else {
Log.d("zil", "degisti");
// Do whatever you want to do with the event here
}
unregisterReceiver(receiver);
this probably wont work because you created an Anonymous inner class implementation of BroadcastReciever. instead create a nested/private class that extends BroacastReceiver in the activity where you want your service started. Then dynamically register and unregister your receivers in the Activity lifecycle callbacks
I register receiver from the onCreate from my activity like this
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
BroadcastReceiver mReceiver = new ScreenOnOffReceiver();
registerReceiver(mReceiver, filter);
And everything works good and the receiver get the intents, and everything is working good until, i close the activity. When I close the activity the method doesn't receive intents any more...
Does someone one know how can I register for receiver . . .
Note : I do not unregistered the receiver , but it happens somehow magically it just stop working properly . . .
The idea of registering a broadcast receiver in an activity is to get notified of some event while the activity is on (register the receiver in onResume, unregister it in onPause).
If you need a broadcast receiver to handle the event while the activity isn't showing, then register your broadcast receiver in your manifest.
If you need to handle both cases in a different way, then use a ordered broadcast.
If you want to receive messages all the time than you will need to create your own service and do your intent filter in onStartCommand method and unregister in onDestroy.
More details here http://developer.android.com/reference/android/app/Service.html
i have a widget which needs to listen to BATTERY_CHANGED event, however, since this event is protected and cannot be declared from the manifest i create a new BroadcastReceiver from the Application constructor:
public void onCreate() {
super.onCreate();
if (DEBUG) Log.d(TAG, "onCreate()");
// Register receivers
if (receiver == null) {
receiver = new MYReceiver(this);
}
// Create new intentfilter
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
registerReceiver(receiver, intentFilter);
}
Then, from the Receiver i call a static method of the AppWidgetProvider which actually update the widget using RemoteViews. Everything works flawlessy until 1 hour as passed, after that time my Receiver disappears and the widget does not update anymore. I'm testing this on a Droid with 2.2.1 firmware-
What i'm doing wrong? Is this the correct way to update the widget (i just need that event so i don't want to have a service if its not needed). Should i use an AlarmManager to be sure from time to time that my receiver is still there? I can i do this?
Thanks.
I don't have a clue why your receiver got lost after an hour but what about using the AlarmManager to check periodically if it is still there? So you can re-register it if it got lost.