I have a service (with a wakelock) that must run continuously behind the scenes capturing user Geo Location. The Service implements the LocationListener methods (i.e. onLocationChanged()).
However it takes some time for onLocationChanged() to get invoked by the phone, so in the meantime my service has to do something. I thought of using Thread.sleep(), but will that prevent the phone from invoking onLocationChanged()? Or should I do polling: while(i < 1000,000) {++i;}?
I'm not getting such abundant GPS results using either of those ideas; wondering if anybody can give me a tip on how to accomplish this.
I think you can use wait(), and notify() with synchronize block with LocationListener instance.
search for samples using wait(), notify().
I guess you want to keep the service "alive" while it is waiting for location changed information. That is taken care of by the system and you do not have to add code for that. When location change information becomes available, the onLocationChanged() would be invoked in the context of your service.
I solved the problem by removing WakeLock (waste of battery), doing a 10-second busy wait/Thread Sleep (just in case one blocks the GPS invocation of onLoc()), and using AlarmManager to wake the device from sleep and start the service.
This: gets GPS during sleep AND doesn't drain battery power.
Related
I'm working on an android app where I need to get location updates in the background for an extended period of time using the GPS provider, so I need the location udates to occur when the user is no longer interacting with it. I did some testing of my own comparing LocationManager's requestSingleUpdate (the provider, pendingIntent version) and requestLocationUpdates (the provider, minTime, minDistance, intent version). After taking a good bit of data on my Droid Razr HD, it looks like using requestLocationUpdates is significantly more reliable than requestSingleUpdate (for both methods I actually compared the GPS location reported to where I actually was, i.e. not using the reported accuracy, and requestLocationUpdates was not only significantly more accurate as to my actual location, but it returned a location fix time that was the same as the current time far more often then using the requestSingleUpdate option). I know how to use AlarmManager with a repeating alarm and call requestSingleUpdate so that I only need to hold a wakelock each time the the alarm goes off, but because of the increased accuracy of using requestLocationUpdates (at least in my tests on my phone) I would like to use that method instead. My problem is that if I use the requestLocationUpdates method, I am really unclear as to what I have to do in terms of holding a wakelock to keep the updates occuring when the user isn't interacting with the phone. I am calling requestLocationUpdates from a separate thread that is launched from a service (I read that that is the standard pattern). My question is, do I have to hold a wakelock for the entire time that I want location updates to keep coming? If I don't get my own wakelock do the location updates keep coming, waking the phone up for each new update? If this is true, do these updates create their own wakelock, and if so, when do they release the wakelock? I can't seem to find a clear answer on this. Any help is greatly appreciated.
No you don't need a wakelock because the OS takes the wakelock for you (code). The wakelock is released when onLocationChange() ends or when your broadcast receiver receives the intent (for the intent version of the interface). You need your own wakelock if you start some async work in onLocationChange() for example with an other thread.
I wrote a flight logging app which also needs update every few seconds to recognize take-oofs and landings. The received data is evaluated in a service. To keep the service alive you will need a WakeLock. I get the lock when the detector (automatically recognizing the relevant events) is started and I release the lock when the user turns the detector off; this is also the life time of the service, so the lock is aquired in onCreate and it is released in onDestroy. I use a SCREEN_DIM_WAKE_LOCK to save some power.
My application requests for updates in a service on background when a boolean flag is set to true. If flag is set to true, then i acquire a PARTIAL_WAKE_LOCK to let my background service run.
My questions are:
Since I requested for updates from location manager ( i don't manually request updates but subscribed for locationManager.requestLocationUpdates )... does the locationManager keep working as normal/usual even if device goes to sleep with PARTIAL_WAKE_LOCK ?
I've read there is a WifiLock -> WIFI_MODE_SCAN_ONLY that I'm not acquiring. Since location manager uses wifi scans to detect location through wifi hotspots, should I acquire this as well ?
What about gps location updates when device goes to sleep ?
no, it does not. More (very good) info here, including possible solutions/ hacks.
regarding 1, I would have to make an educated guess and say it wouldn't make a difference
from what I can gather, it doesn't make a difference which provider you are using for the updates, LocationManager.NETWORK_PROVIDER or LocationManager.GPS_PROVIDER.
in danger of going a bit OQ, I am a bit curious which kind of application would need to aquire a wake lock to keep a service running at all. As far as I know, having a wake lock doesn't ensure your Service keeps running. The only thing which ensures a Service keeps running is to have it in the foreground (Service.startForeground()). Otherwise the system still might kill the service, regardless if it aquired a wake lock or not.
That being said, if it is running, it can do it's work with a Handler or something.
If you are using this approach, and I think you are based on the scenario, I would advise against it. Basically you are creating a service, have it run in the foreground (guess) AND you are aquiring a wake lock just to request for location updates when the screen is off. This seems a bit overkill.
There's a more efficient way, which has the benefit it has by far more accurate timing then the dreaded timing of Handler.postAtTime or Handler.postDelayed: AlarmManager.setRepeating(). Set type to ELAPSED_REALTIME_WAKEUP or RTC_WAKEUP so it will run if the device sleeps, then when the alarm event is fired and received by a BroadcastReceiver you will have to create, you could request for updates and handle other events.
If you're not using a Handler, but are merely requesting location updates, this approach still probably would be better, because it doesn't require you to have a running Service or to acquire a wake lock.
And it seems LocationManager.addProximityAlert() is the way to go here. Which is flawed as well (see 1)
Similar question here by the way: Android: GPS location updates when the cellphone is in sleep?
I've spent days trying to get WiFi and cell-based locations with locked screen with Android 6.0 on Nexus 6. And looks like the native android location service simple does not allow to do it. Once device got locked it still collects location update events for 10-15 minutes then stops to providing any of location updates.
In my case the solution was to switch from native Android location service to Google Play Services wrapper called com.google.android.gms.location: https://developers.google.com/android/reference/com/google/android/gms/location/package-summary
Yes, I know that some of Android devices lack of GMS, but for my application this is the only solution to perform.
It does not stop sending location updates even when in the background and device screen is locked.
Me personally prefer RxJava library to wrap this service into a stream (examples included): https://github.com/mcharmas/Android-ReactiveLocation
I developing an app which tracks a user via GPS and reminds them if they cross a toll bridge.
I obviously need the GPS location listener to run in a service and I'll also need a partial-wakelock so it can run occasionaly when the phone is asleep.
I also want the GPS updates to vary in frequency depending on the distance from the toll bridge to save battery.
The cwac- WakefulIntent service seems ideal for what I'm trying to achieve.
However, there are a couple of problems I can see me having before I head down this route (if you pardon the pun ;-).
Does the WakefulIntent service exit and release the wakelock once doWakefulWork() completes even if I'm waiting for my locationlistener to return some GPS updates.
How can I prevent doWakefulWork for returning until I get a location update and cleanup my listener.
What happens if I'm still waiting for a GPS update when alarm manager starts the service again, i.e. before doWakefulWork() has completed?
How can I persist data between instanciations of the service. Can I stuff an array of GPS co-ords into SharedPrefs?
Finally, as I get closer to a toll bridge I need more GPS frequent updates. Do I manage that within doWakefulWork() or by altering scheduleAlarms() so that it uses setRepeating() with a number of minutes stored in SharedPrefs by the service. The idea here is to throttle GPS usage based on proximity to an area of interest.
While the demo app provides a template to work from, I haven't been able to find any solid examples of WakefulIntentService doing any asynchronous jobs.
The cwac- WakefulIntent service seems ideal for what I'm trying to achieve.
Not really. IntentService is not good for location tracking, because you cannot register a listener. The service will shut down once onHandleIntent() ends.
Personally, I would use addProxmityAlert() on LocationManager, rather than mess with any of this yourself.
Does the WakefulIntent service exit and release the wakelock once doWakefulWork() completes even if I'm waiting for my locationlistener to return some GPS updates.
Yes.
How can I prevent doWakefulWork for returning until I get a location update and cleanup my listener.
You don't. You use something else, such as LocationPoller, or, better yet, addProximityAlert().
What happens if I'm still waiting for a GPS update when alarm manager starts the service again, i.e. before doWakefulWork() has completed?
You ensure that you have appropriate timeout logic in place to prevent this, such as can be found in LocationPoller.
How can I persist data between instanciations of the service. Can I stuff an array of GPS co-ords into SharedPrefs?
Yes, or a database, or a file in a format of your choosing.
Finally, as I get closer to a toll bridge I need more GPS frequent updates. Do I manage that within doWakefulWork() or by altering scheduleAlarms() so that it uses setRepeating() with a number of minutes stored in SharedPrefs by the service.
You would change your alarm schedule.
I haven't been able to find any solid examples of WakefulIntentService doing any asynchronous jobs.
WakefulIntentService is the "asynchronous job". It does not execute other asynchronous jobs.
this scenario is very common according to the Android documentation but still I don't find a straight solution neither there nor anywhere on the net.
So I have a service that should do something like this:
Register a LocationListener to receive the user location
Once the LocationListener is called - stop listening for a 5 minutes
After 5 minutes start listening again and loop from 1
This is the recommended way to save battery power while listening for the user location.
As a service I have a major problem with step 3.
The only way I found to "wait" for 5 minutes is to schedule a java.util.Timer to execute a TimerTask in 5 minutes and this TimerTask should register the LocationListneres again.
However this does not work because of:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
Which is also expected because requestLocationUpdates should be called from a "main" thread.
Ok .. nice... but I don't have a Main thread. I don't have an activity. From the TimerTask I can't send an intent to the service to register my listeners back.
How can I ask my own service to register my listeners again?
This is the recommended way to save battery power while listening for the user location.
Really? The only way that's a good pattern is if you are using AlarmManager for the five-minute delay, so the device falls asleep in between location checks.
The only way I found to "wait" for 5 minutes is to schedule a java.util.Timer to execute a TimerTask in 5 minutes and this TimerTask should register the LocationListneres again.
And that would be a horrible use of battery, because it would mean you would need to keep the device powered on constantly, not allowing it to go to sleep.
I don't have a Main thread
Yes, you do. All processes have a main application thread. onCreate(), onStartCommand(), etc. of a service are called on the main application thread.
I don't have an activity.
Then you better write one, as your app will not work on Android 3.1+ without it. Your app will not run until a user launches one of your activities on Android 3.1+.
How can I ask my own service to register my listeners again?
What you are trying to accomplish is a rather complex problem. Not only do you need to arrange for the device to fall asleep and wake back up again, but you also need to deal with lots of edge cases (e.g., what if no location is available, because the device is in airplane mode or is underground or something?).
I wrote LocationPoller to handle your use case, and another developer forked it to create a more feature-rich implementation.
Whether you use one of these directly or simply examine their implementation, they should be useful to help you understand how to solve this problem. All of the details, though, are well beyond the scope of a StackOverflow answer -- it would take several pages in a book to explain it all.
You can specify the parameter in requeestLocationUpdates() to make it run after a certain time.
I have an android application. Based on the current geo location of user, I want to fetch some remote data in background and store it. My implementation is:
At specific interval a alarm fires up my service. Service uses an anonymous class to query current location and registers a locationListener callback. On call of onLocationChanged() I initiate the remote data fetch from server.
However once my service is done registering the location listener using anonymos class, it returns as expected; as it doesn't wait for callback to happen before finishing. Since callback takes some time and makes a call when service has already returned, it throws an error saying:
java.lang.RuntimeException: Handler{43e82510} sending message to a Handler on a dead thread
Which is quite understandable. One quick workaround for me now is that I can use getLastKnownLocation from locationManager as that doesn't respond back by callback; but what if I do want the latest location right now, in a service and not activity? How can I wait for callback to happen and stop my service from returning.
Also, at what point does lastKnownlocation gets updated? Everytime GPS registers a new location; does it update it? What I want to know is that if it's not latest can it still be closed to latest? As I didn't see an option in android emulator to configure the time period between subsequent updates.
Any help is much appreciated.
Cheers
but what if I do want the latest location right now, in a service and not activity?
Sorry, but that is not possible, in either a service or an activity. For example, if the GPS radio is off, and you are requesting location data from GPS, it will take tens of seconds just to get a fix, and that's if you are lucky. It might not get a fix at all.
How can I wait for callback to happen and stop my service from returning.
You don't. You do what you said you would do:
use getLastKnownLocation from locationManager as that doesn't respond back by callback
So, have your Service (which is hopefully an IntentService) check to see if getLastKnownLocation() happens to have a value. If it does, use it. Otherwise, registerLocationUpdates() using a PendingIntent that will pass control back to your IntentService. When you get that Intent, use the location and unregister for updates (assuming the alarm period is nice and long, like, say, once an hour).
Things get tricky if your alarm is a _WAKEUP alarm. You will then need to hold a WakeLock, so the device does not fall back asleep while you are trying to get a GPS fix. However, you need to release that WakeLock sometime, and if we cannot get a GPS fix...ummm...well, that's the tricky part. Trying to figure out a nice clean way of handling this, and implementing it as a reusable component (e.g., LocationAlarmService), is one of 18,000 items on my to-do list.
Also, at what point does lastKnownlocation gets updated? Everytime GPS registers a new location; does it > update it?
AFAIK, yes.