I'm trying to implement an app that times how long my phone screen is on throughout the day using a broadcast receiver.
I'm declaring Action_Screen_Off/Action_Screen_On in my broadcast receiver since I can't declare it in my manifest, and I've been debating on the best way to handle storing the amount of time that my screen was on.
Since I can't declare it in the manifest, Should I declare the broadcast receiver inside of the onCreate in my activity? My worry with that is, if my understanding is correct, is that my receiver would then be tied to the lifecycle of the activity and I would only be able to store the on/off times whenever the activity is active.
The whole point of the app is that it's working in the background, and then displaying graphs of usage once an activity is in the foreground.
This led me to think that a Service might be the best bet the handle the Broadcast receiver, but Google seems to now be recommending that we don't use background services, only bounded and foreground services.
How can I make sure that my app is receiving the on/off intents, without the activity that declares the receiver being in the foreground, and the receiver not depending on the lifecycle of that activity?
You need a background Service for this functionality. Your Service doesn't need to actually do anything, but it needs to be active all the time so that you have something to anchor your BroadcastReceiver to. In onCreate() of your Service, create an instance of the BroadcastReceiver and register for the screen on/off events. Make sure that you return START_STICKY from your onStartCommand() in your Service. This will ensure that the Service is always active, and Android will restart the Service if it kills off your process (for whatever reason). The BroadcastReceiver can just write the timestamps of the on/off events to a file, SQLite database or SharedPreferences and your Activity can then read this data and show the graphs or whatever.
Related
I'm using BroadcastReceiver in activity to receive message from others services. It works well, but the problem is that
When my app goes to the background, the BroadcastReceiver will be unregister from the activity. so the messages which are received before the activity go to front will be lost.
How to handle the case?
Scenario A: Only The Activity
If you only need to receive the broadcast when you have an activity in the foreground, have the activity register the BroadcastReceiver using registerReceiver(). As #MisterSquonk indicated, you would register the receiver in onResume() and unregister it in onPause().
Scenario B: Activity If In Foreground, Else Other; Ordered Broadcast
If you want the foreground activity to handle the broadcast, but you want something else to happen if that activity is not in the foreground (e.g., raise a Notification), and the broadcast is an ordered broadcast (e.g., incoming SMS), then you would still use the Scenario A solution, but with a higher-priority IntentFilter (see setPriority()). In addition, you would register a BroadcastReceiver via a element in the manifest, with a lower-priority for the same broadcast. In the activity's BroadcastReceiver, call abortBroadcast() to consume the event and prevent it from reaching your manifest-registered BroadcastReceiver.
Scenario C: Activity If In Foreground, Else Other; Regular Broadcast
If Scenario B almost fits, but the broadcast you are listening for is not an ordered broadcast, you will need to start with Scenario B. However, have the broadcast that both receivers have in their respective filters be one of your own, using a private action string as #MisterSquonk suggested. In addition, have another BroadcastReceiver registered in the manifest, whose is for the real broadcast you're listening for. That receiver would simply call sendOrderedBroadcast() to send out the ordered broadcast that the other receivers are listening on.
Scenario D: Activity Regardless of Foreground
If some activity of yours needs to know about the broadcast, and it does not matter whether or not it is in the foreground, you need to rethink what you mean by that. Usually, this really means that the broadcast affects your data model in some way, in which case your concern should not be to let the activities know, but rather to update your data model, and use your already-existing "let the activities know about the data model change" logic handle the rest.
If, however, you are convinced that this is not part of your data model, you can implement Scenario B or Scenario C, plus stick some information in a static data member. Your activities can examine that static data member in onResume() to pick up the information about the broadcast when they return to the foreground.
If you're thinking "but, what if my process is terminated between the broadcast and the other activity coming to the foreground?", then your broadcast really is updating your data model, per the opening paragraph of this scenario.
If you're thinking "but, I want to update an activity that is doing work in the background", then the activity in question is broken. Activities should never be doing work in the background. That work should be delegated to some form of service, and there's a whole related set of scenarios for getting a broadcast to the service.
If you declare the BroadcastReceiver in the Manifest, it will always be active and be called even if the application is closed.
I have an application that makes async HTTP requests from various places (app activities and a background service). I'd like to catch response events inside my main activity and modify some views. This is achieved by using anonymous class BroadcastReceiver inside the main activity. The registering/unregistering of the broadcast receiver is inside onResume()/onPause().
The problem is that when screen is off and the activity is not in the foreground the events aren't caught, because the receiver is unregistered. How to catch all events even in background while preserving register/unregister coherency of BroadcastReceiver?
Your best bet here would be to start a persistent background service (with a local broadcast receiver).
Here are some starting points:
Your service's onStartCommand() should return START_STICKY, so
it's not killed by the OS.
You should create a local variable inside
the Service that holds your broadcast receiver and register this
receiver in onStart() and unregister it in onDestroy().
Start the
service whenever you find suitable (e.g. onCreate() of the
Application, since it's only called once per application life-cycle
and is not tied to a specific Activity).
This answer might help.
Your existing approach doesn't work because when the screen is turned off, the onPause signal is sent to all your activities and they automatically unregister the local broadcast receiver (and they should be).
There two alternatives
Have a service running and register the receiver there instead.
You can register the broadcast receiver in the manifest and handle it there. Please keep in mind that the receiver will run on the main thread, so you should signal to a running service perhaps a service that performs a single task.
A service that performs a single task can be implemented using IntentService. It is kind of like an async task wrapped in a service.
I solved the problem by adding EventBus lib. The handler is implemented inside the main activity, activity subscribes for events on onCreate() and unsubscribes on onDestroy(). Since EventBus lib is built on standard Java components I expect the garbage collector to automatically clean up everything even if onDestroy() is not called.
Futhermore I used WeakReference for my views which allows to check if an activity is already disposed to prevent unexpected errors.
This may be not the best solution, but it works for now and much easier to implement than other proposed answers.
I need to check for net connectivity in my application. Nothing should work if there is no internet connectivity. This I have implemented using BroadcastReceivers, but I want the receivers to be unregistered (i.e. not getting called) when my application is in background. The receiver should only work when the user is using the app.
Initially, I had a broadcast Receiver registered in my manifest, but I noticed it got fired even when my app was in background. So, I chucked the idea.
Then, I registered the receiver in onResume(), and unregistered in onPause(). But, the problem with this is that if I go from activity A to activity B of my application, then receiver is unregistered on onPause() of A and again registered in onResume() of B. This makes the activity transition heavy. Even though, in such a case the unregister and register process shouldn't happen.
I only want the receiver to get unregistered when the user stops using the app, not during activity transitions, but it should also not keep running when app is in background. I thought of using services, but I want to detect change in net connectivity, which is done best with receivers.
So, is there a way to detect when the app goes in background so that I can unregister my receiver? If not, what is the best way to achieve my requirement?
I have code for registering, unregistering receivers and also for detecting connectivity changes already.
Few days ago I read that there is a better mechanism for sending broadcasts within single application - the LocalBroadcastManager.
It works well (just like standard broadcasts..). However, yesterday I've found out that it cannot send broadcasts to receivers, which are defined in the manifest (when I temporarily switched it to use the standard Activity's sendBroadcast method, it worked).
The reason why I want this (and correct me if there is a more preferred way to do it) is:
Lets's say I want to download a file. I will use a service, because that's how Android wants us to do. OK, now I want to display (and periodically update) its progress in my activity. So service will be sending broadcasts to my activity and the activity has to register to receive them. The preferred way to handle broadcasts is to register in onResume() and unregister in onPause(). Now let's imagine that the user is bored with the slowly moving progressbar, so he presses Home and goes to do something else. Later he comes back and wants to see the current status of the download, but how can I tell him, when I unregistered from broadcasts that second he left my application?
That's why I use a receiver defined in the manifest, to be always ready to receive the broadcast and store it permanently (shared preferences, database...), so the activity can reconstruct the latest broadcast when it becomes visible.
However now I'm not sure, whether this routine is not recommended, or why the LocalBroadcastManager is not allowing me to do it.
If you are using SharedPreferences a workaround would be to make your activity implement OnSharedPreferenceChangeListener. So the service writes the pref and the activity listens for the change and updates progress bar. onResume() you also check the preference and update the UI accordingly.
The nice thing with this is you don't really have a leak if you fail to unregister them - see
Android : Where should a OnSharedPreferenceChangeListener be defined/registered - I prefer to unregister to onDestroy() as I want to have my activity updated even if not in the foreground - and the listener will go away even if onDestroy is not called.
As for why it does not work with manifest registered receivers - could you post some code ? Do you actually register the receivers with LBM ?
I have built an application which implements a number of broadcast receivers and registers them within a service based on user settings. The service is bound to an activity which calls some of its methods.
When a broadcast receiver is called it starts the service (or calls onstart of the service if it is already running) and passes it a string telling the service what to do. My problem is when the activity is destroyed (back button) the service is also destroyed which in turn kills the broadcast receivers.
I know I can register the receivers in the manifest which would mean doing a check when they are called to see if the user has selected that option. However one of the receivers critical to the application is 'android.intent.action.HEADSET_PLUG' which can only be registered programatically.
So I guess my question is, is there a way to keep this broadcast receiver active when the service is destroyed?
If not can anyone see a workaround for this issue?
Thanks,
Rob
My problem is when the activity is killed the service is killed which in turn kills the broadcast receivers.
If by "killed" you mean the user terminated your app with a task killer or "Force Stop" in the Settings app, then "killed" is the appropriate verb. However, your whole process is "killed" -- it does not follow the chain of events that you describe here.
If by "killed" you mean the user exited your activity via the BACK button, that is because you elected to bind to the service, rather than start it. If you want the service to continue executing past the lifetime of the activity, you must use startService(), and ensure that there is some path by which the user can indicate that they no longer want this service, so you know when to call stopService().
So I guess my question is, is there a way to keep this broadcast receiver active when the service is killed?
No.
If not can anyone see a workaround for this issue?
Start your service, instead of (or possibly in addition to) binding to the service.