We needed a location service for our app that was available from anyplace.
We used s singletone with Application context for system services and more, and has two basic methods start and stop which listen to location providers and stop listening respectively.
We have getLastLocation method that retrieves the current most updated and accurate location we could find.
We have another method that gives me a headache :-)
Location getLocationWithWait(Class c) which supposed to get a location if available, if not it will return null and will create a Timer for 45 seconds.if the 45 seconds have passed and no location was found then the timer will broadcast to the class given in the parameter a 'no location' broadcast, otherwise if the location callbacks will be called they will cancel the timer and will send 'location found' broadcast to the class in the parameter.
So here are my questions:
i started to think the whole
architecture here is wrong, any
better way to implement a location
service to cater ANY Activity in my
application ?
i used a Timer an not Handler since
the singletone i use is NOT an
activity so i have no Looper an
creating a thread with looper looks
to me just as bad as creating
another Thread for the timer... i
did wanted to use the Activity
instead, but then... if the activity
pauses and resumes i need to keep
track of the timer's remaining time.
the broadcasts may also be of a
problem since if the activty pauses
it will miss the broadcast and then
i need to keep track in my
singletone after several states,
StickyBroadcast may solve it but
that one i can't send to specific
class but to the whole system only.
So finally will it be any advantage to make this class a Service ?(to be honest i thought of maybe one advantage but not much) i want a location service with timeout much like google do in their "My Location" in maps.
10x.
Wouldn't it be better to use a LocationListener, as described in Requesting Location Updates?
You can then use a 'FastFix' in onResume()
Without knowing a bit more about your requirements, it's difficult to make more specific suggestions.
Hope this helps,
Phil Lello
Related
More activities need to get informations about location, so I don't think would be a good idea making each of them a location listener.
For this reason my idea would be letting a background service listen for changes, then when an activity wants to know current latitude/longitude it just asks them to service.
Problem is that, when current activity goes on pause (screen fades, user presses home button,ecc.), service should stop listening (in order to avoid battery waste).
Can you suggest me a good pattern to achieve what I'm trying to do?And is it, according to you, the right way to proceed?
You should create a bound service - this service is stopped, once all bound activities are deleted (not onPause...).
For onPause detection you need to overwrite the application class and create a static value "inForeGround".
Here are some infos for a bound service!
Little Flyffy Location Library
Nofity your application when location are changed.
Simple, fast, easy!
http://code.google.com/p/little-fluffy-location-library/
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 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.
I need to perform the follow logic in my application:
Every minute, I want to be able to listen to GPS location for 20 seconds to get a GEO-location fix.
This obviously needs to run a different thread than the UI thread.
I am however having some problems with using looper and timertask in conjuction...
What's the best way to achieve this?
I guess you need to use a Service :
Android doc :
A Service is an application component representing either an application's desire to perform a longer-running operation while not interacting with the user or to supply functionality for other applications to use.
So the Service start the LocationManager using requestLocationUpdates() and implements LocationListener.
Then you have (at least) two solutions (depending on what you want to do) :
dispatch the event to the Activity that need to use the Location ( with a Broadcast for example )
the Activity has an access to the service and uses a getter to get the latest location.
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.