Situation: My program has parts that are heavily location based, but do to speed issues for when the location is actually needed, I don't have time to lock. The solution I have designed is to get location information during primary operation (read: main screen) so that the location is available when the specific pieces need them.

Right now I register for updates and in onLocationChanged it checks if the location is accurate enough. If it is it calls removesUpdates.

Problem: If the device is somewhere that it can not get an accurate location (or any location) the GPS doesn't shut off, the batters overheat, and the users get very upset.

Question: Is there a good clean way to check if the GPS is failing to get a lock, and tell it to give up at a certain point? I created a thread timer, but because the request is tied to onPause/onResume I do not want to create extra threads that may get all tangled up.

有帮助吗?

解决方案

Further to Merlin's answer (I was just typing this lot out in notepad when it appeared) - I agree. My suggestion is:

Facing a similar problem, I decided that the best thing to do would be to decouple the whole GPS from the main activity by means of a service.

By this I mean have a service which does the requestsLocationUpdates() and removeLocationUpdates() and implements a LocationListener. This service provides methods which the main activity can call by means of an IBinder interface. It also sends broadcasts to the activity which implements a BroadcastReceiver to listen to these messages.

So one of the the service methods your main activity could call would be (say)

mLocnServ.startGPS(int timeout, float requiredAccuracy, int minUpdatePeriod, int minResendDistance)

where mLocnServ is the binder interface exposed by the service.

The last two arguments being those to pass as arguments to requestLocationUpdates in the service. (personally I don't think these make any difference whatsoever to when the GPS turns itself off, as far as I can see it runs all the time until removeUpdates() is called). Anyway the first argument (timeout) should be the time you are prepared to wait for a fix of the required accuracy (argument 2).

So in your service you will need a Runnable as a timer, which if it times out wil send a broadcast of type TIMED_OUT (say) and removeUpdates to stop the GPS. In your onLocationChanged you can test the location you get against the required accuracy and if good enough, send a broadcast of type GOT_A_FIX (say) and pass the location (lat/lon and accuracy) as extras in the broadcast, then removeUpdates to stop the GPS. (TIMED_OUT and GOT_A_FIX are just example names for enums which you can make up to distinguish between the broadcast message types)

The main activity can decide what to do then in its BroadcastReceiver onReceive(), i.e whether to try again if it got a TIMED_OUT broadcast or what to do with the data it got from the GOT_A_FIX message.

You'll probably also need a mLocnServ.stopGPS in the binder so that you can shut the GPS no matter what the service is doing

其他提示

Use a service to encapsulate this functionality. Run an asynchtask from inside that.

You can use binding to handle interaction with activities where necessary

Is there a good clean way to check if the GPS is failing to get a lock

Yes, there are some cases where GPS fails to get a fix for a long time. From my experience, these are :

  • No assisted data. You see, the GPS chipsets in phone have several constraints (battery, speed etc) , hence they are slow at latching on to a fix. The GPS chipset has to scan the spectrum for satellite and that takes a while. Assistance information is send via the internet. This contains Almanac data that has the satellite positions and the frequencies informations, so this shortens the GPS signal searching time. No internet means the GPS chipset will take more than 2 minutes for getting a fix (this is called standalone GPS) . This time varies for chipsets, terrains, weather etc.

    (tldr : check if internet is accessible, if it isn't you should expect a long TTFF (time to first fix)

  • Low satellite visibility : This happens in indoor cases. Even if the GPS chipset has assistance data. It cannot see the satellites because it is indoor. This means the satellite signal to noise ratio is low, or the number of visible satellites is < 4. In theory 2 satellites are enough. But in practice I've seen at least 4 satellites are needed for a proper fix.

    (tldr : Use the NMEA listener/GPS status listener to see how many satellite is visible/used. Atleast 4 satellites must be used for a fix)

  • Hardware/Software problems : You can't do a lot about this. Some GPS chipsets allow you to send extra information to 'reset' the GPS cached data. Look out for huge TTFF times and other such abnormal GPS patterns, use a time-out mechanism.

This is mostly written from a GPS point of view, so don't mind if this does not make a lot of sense.

I had a similar issue. I wanted to be able to get GPS coordinates across all my activities, but did not want to implement a superclass w/ GPS listener, sometimes if an intent called the same activity, I ran into some issues of GPS getting stuck on. Did not want to disable it during onPause..

Basically I created a service that gets the GPS updates, then I count how many listeners have connected/disconnected to my service. If callbacks = 0, then I stop GPS. If callbacks = 1 I start it.

This seems to work pretty well, and seems to be a pretty fool proof way to handle GPS updates across the entire application. The good thing is that when I unregister my callbacks in onStop, my onStart will actually connect first before the onStop gets called from the previous activity. This means my GPS will not miss a beat.

I implemented a superclass that connects & implements the callbacks for my service (via aidl). That way every activity class has access to the information just as if it was implemented in the Activity.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top