I've set up the LocationManager to get the current location every 2 minutes:
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 120000, 0, this);
This works fine and onLocationChanged is called every 2 minutes as expected. However, it seems that it is being called multiple times over a 10-40 (a random amount) second span every 2 minutes. I log every location received in the onLocationChanged so here are some samples to get an idea of what is going on:
At 17:30
GPS 32.0 50.66318929195404 10.735434293746948 0.0 2010.08.07 17:30:10
GPS 32.0 50.66315710544586 10.735423564910889 0.0 2010.08.07 17:30:14
GPS 32.0 50.66314101219177 10.735418200492859 0.0 2010.08.07 17:30:17
GPS 32.0 50.66314101219177 10.735418200492859 0.0 2010.08.07 17:30:20
GPS 24.0 50.66313564777374 10.735418200492859 0.5 2010.08.07 17:30:24
GPS 32.0 50.663098096847534 10.735573768615723 0.0 2010.08.07 17:30:28
GPS 32.0 50.663065910339355 10.735611319541931 0.0 2010.08.07 17:30:31
Then I get no more updates for 2 minutes.
At 17:32
GPS 32.0 50.661821365356445 10.737022161483765 1.0 2010.08.07 17:32:39
GPS 16.0 50.66170871257782 10.737043619155884 1.8200275 2010.08.07 17:32:45
GPS 24.0 50.661579966545105 10.737027525901794 1.25 2010.08.07 17:32:50
GPS 16.0 50.66150486469269 10.73712408542633 1.0 2010.08.07 17:32:55
GPS 12.0 50.661579966545105 10.73715090751648 0.9013878 2010.08.07 17:33:01
GPS 24.0 50.66139221191406 10.737038254737854 1.5811388 2010.08.07 17:33:06
GPS 16.0 50.66141366958618 10.737301111221313 0.70710677 2010.08.07 17:33:12
GPS 16.0 50.66141366958618 10.737301111221313 0.70710677 2010.08.07 17:33:12
GPS 24.0 50.661311745643616 10.737070441246033 1.118034 2010.08.07 17:33:16
GPS 16.0 50.66122591495514 10.737177729606628 1.118034 2010.08.07 17:33:22
GPS 12.0 50.66124200820923 10.737220644950867 1.3462912 2010.08.07 17:33:26
GPS 12.0 50.661311745643616 10.737268924713135 3.6055512 2010.08.07 17:33:25
And so on... then another set of updates 2 minutes later at 17:35.
Is this the standard behavior? I was expecting to get only one location every 2 minutes, and the timespan in which it gives me location updates seems rather random. Ideally I would prefer to only get one location... is there a way to do this?
From the documentation of requestLocationUpdates(String provider, long minTime, float minDistance, LocationListener listener) concering the minTime parameter:
"the minimum time interval for notifications, in milliseconds. This field is only used as a hint to conserve power, and actual time between location updates may be greater or lesser than this value."
So the answer to your questions, yes this is standard behavior and, no you cannot change this.
If this is a problem for you, you could ignore calls to the callback method if a certain amount of time hasn't passed.
I found this question because I had the same problem.
I believe I have the answer. The rapid updates are being fired because you have the meters parameter set to 0.
Change the meters parameter to something like 10 and it will only fire the LocationChanged event every 2 minutes IF your location changed by 10 or more.
Before I made this change, LocationChanged was firing multiple times a second. Now, it fires once. Then every 2 minutes, you will see the GPS icon on the status bar, but unless your location changed, the event doesn't fire.
I hope this helps. This is what fixed it for me. Didn't have to add any extra logic to prevent false fires.
this is my LocationListener implementation to filter out unnecessary onLocationChanged() events:
NOTE I use messages in my service.
public class GPSlocationListener implements LocationListener
{
//member variables
private Handler mParentHandler;//points to Handler of parent
private long mTimeBetweenLocationEvents;
private long mTimeOfLastLocationEvent;
private boolean mAccuracyOverride;
private float mLastAccuracy;
private boolean mOverrideLocation;
//constants
private static final float INVALID_ACCURACY = 999999.0f;
private static final String TAG = "GPSlocationListener";
//constructor
public GPSlocationListener(Handler parentMsgHandler, long timeBetweenLocationEvents, boolean accuracyOverride)
{
mParentHandler = parentMsgHandler;
mTimeOfLastLocationEvent = 0;
mAccuracyOverride = accuracyOverride;
mLastAccuracy = INVALID_ACCURACY;
mOverrideLocation = false;
mTimeBetweenLocationEvents = timeBetweenLocationEvents;
}
//EVENT: onLocationChanged()
// send GPS coordinates to CommService
public void onLocationChanged(Location loc)
{
Log.d(TAG, "onLocationChanged() triggered. Accuracy = "+Float.toString(loc.getAccuracy()));
mOverrideLocation = false;
if (loc != null)
{
//if a more accurate coordinate is available within a set of events, then use it (if enabled by programmer)
if (mAccuracyOverride == true)
{
//whenever the expected time period is reached invalidate the last known accuracy
// so that we don't just receive better and better accuracy and eventually risk receiving
// only minimal locations
if (loc.getTime() - mTimeOfLastLocationEvent >= mTimeBetweenLocationEvents)
{
mLastAccuracy = INVALID_ACCURACY;
}
if (loc.hasAccuracy())
{
final float fCurrentAccuracy = loc.getAccuracy();
//the '<' is important here to filter out equal accuracies !
if ((fCurrentAccuracy != 0.0f) && (fCurrentAccuracy < mLastAccuracy))
{
mOverrideLocation = true;
mLastAccuracy = fCurrentAccuracy;
}
}
}
//ensure that we don't get a lot of events
// or if enabled, only get more accurate events within mTimeBetweenLocationEvents
if ( (loc.getTime() - mTimeOfLastLocationEvent >= mTimeBetweenLocationEvents)
||(mOverrideLocation == true) )
{
//be sure to store the time of receiving this event !
mTimeOfLastLocationEvent = loc.getTime();
//send message to parent containing the location object
Message msgToMain = mParentHandler.obtainMessage();
msgToMain.what = Constants.MSG_LOCATION_CHANGED;
msgToMain.obj = loc;
mParentHandler.sendMessage(msgToMain);
}
}
}
public void onProviderDisabled(String provider)
{
// TODO Auto-generated method stub
}
public void onProviderEnabled(String provider)
{
// TODO Auto-generated method stub
}
public void onStatusChanged(String provider, int status, Bundle extras)
{
// TODO Auto-generated method stub
}
}
this is implemented as follows in your main code:
//create the APIthread (which exposes mAPIhandler back to this service)
mAPIthread = new APIthread(mApiHandler);
mAPIthread.start();
//use the LocationManager class to obtain GPS locations
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationListener = new GPSlocationListener(mApiHandler, Constants.LOCATION_UPDATE_PERIOD_MSEC, true);
//this will call GPSlocationListener.onLocationChanged()
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
//3 mins NOTE: approximate value
Constants.LOCATION_UPDATE_PERIOD_MSEC,
//no distance updates desired
0,
locationListener);
Related
I'm trying to find a way to turn off the GPS immidietly in case a good enough location was found, while still having a time limit to "give up".
I tried to do this with the following strategy:
start checking for locations, as soon as a location that has an accuracy lower than the maximum tolerated, pass it to the next function for processing and stop looking for updates.
Also, to save battery life, if such location could not be found in 30 seconds, stop looking for location updates without passing a value (basically give up, and hope to better luck next time).
To count the 30 seconds, I'm using a handler. But as soon as I write the line locationManager.removeUpdates(locationListener); in the handler, the locationListener in the parenteses in both lines (the one in the handler and the one in the listener) turns red and reports an error: The local variable locationListener may not have been initialized
Here is my code:
private void checkProximity() {
final LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
//start tracking location
final LocationListener locationListener = new LocationListener() {
...
#Override
public void onLocationChanged(Location location) {
//if new accuracy is better than the best estimate - update the best estimate
if(location.getAccuracy() < MAXIMUM_TOLERATED_ACCURACY) {
//forward location to scanProximity and end the location search
scanProximity(location);
locationManager.removeUpdates(locationListener); //FIRST LINE (see below)
}
}
};
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
500, 0, locationListener);
Handler h = new Handler();
int delay = 30 * SECOND;
Runnable removeListener = new Runnable() {
#Override
public void run() {
//if this code is reached - the maximum tolerated accuracy was not met in the period time
//extended to find a location
//TODO stop the location manager and return without forwarding a value
locationManager.removeUpdates(locationListener); //as soon as I write this line, the FIRST LINE and this line turns red.
}
};
h.postDelayed(removeListener, delay);
}
Is there anyway I can do this differently so I won't get an error?
I recommend you use Little Fluffy Location Library to work with GPS locations. Check out the examples codes and see which makes you more easy the solution to your problem , this is a beautiful way.
my target is to get periodically location updates from network provider using requestlocationupdate() method during certain intervals(x sec), then execute LocationManager.removeUpdates() method to remove updates and achieve an power consumption to be as minimum as possible,
the problem which faced me is the requestlocationupdate() method invoked and call onlocationchanged method every 45 sec, even its "mintime" (2nd parameter in this method) is less than 45 !!, why this happen?
also, the 2nd problem is during each interval, i need to invoke the requestlocationupdates method and records the current latitude and longitude of the user's location and compare it with the recorded latitude and longitude of the last location, if its the same(user still stationary), display "your last location is ...", if happen an change in the location, display "your updated location is ...." .
how i can do it ?
i tried to solve this problem using use handler.post(myRunnable) and calling an runnable object with timertask class to execute requestlocationupdates() method every (x sec) which determined in timertask input parameters.
when i tested this code, its get the latitude and longitude every x sec but its recorded values are changes even i still in the same location!
also,is writing any code in onlocationchanged() override method represents a good approach from side of energy saving?
also, can you tell me how i can get the accuracy of any network provider (wifi/ 3G)?
Any help will be very much appreciated!
Code is looks like:
intializations:
Timer t1;
Timer t2;
TimerTask mTimerTask1;
TimerTask mTimerTask2;
Handler hand;
Handler hand1;
public LocationManager locationManager;
// flag for GPS status
boolean isGPSEnabled = false;
// flag for network status
boolean isNetworkEnabled = false;
Location location; // location
double latitude; // latitude
double longitude; // longitude
double Altitude; // longitude
double accuracy; // accuracy
// The minimum distance to change notifications Updates in meters
private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 0; // 0 meters
// The minimum time between notifications updates in milliseconds
private static final long MIN_TIME_BW_UPDATES = 10; // 10 sec
Handler part:
Runnable run1 = new Runnable() {
public void run() {
mTimerTask1 = new TimerTask() {
public void run() {
hand.post(new Runnable() {
public void run() {
if(check_conectivity()){
//flag1=false;
get_location();
time++;
}
}
});
}
};
t1.scheduleAtFixedRate(mTimerTask1, 0, 10000);
}
};
check_connectivity method:
public boolean check_conectivity(){
// put the reference LocationManger
locationManager = (LocationManager)getSystemService(LOCATION_SERVICE);
// getting network status
// isProviderEnabled ==> Returns the current enabled/disabled status of the NETWORK_PROVIDERr.
// If the user has enabled this provider in the Settings menu, true is returned otherwise false is returned
isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if ( !isNetworkEnabled) {
// no network provider is enabled
showSettingsAlert();
return false;
}
else{
return true;
}
}
get_location method:
public void get_location(){
if (isNetworkEnabled) {
locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER,MIN_TIME_BW_UPDATES,MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
Log.d("Network", "Network");
onlocationchanged() override method:
if (locationManager!= null){
location = locationManager
.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if (location != null) {
latitude = location.getLatitude();
longitude = location.getLongitude();
tv2.setText("Your last Location is - \nLat: " + latitude + "\nLong: " + longitude );
tv3.setText("Last estimeted location number : " + time1);
time1++;
stopUpdating();
can you tell me how i can get the accuracy of any network provider (wifi/ 3G)
As I know you can't. But you can filter responses and tell to device to notify you only if accuracy is ..... .
1st off you can use postDelayed instead post:
private int mSampleDurationTime = 10000; // 10 sec for example
...
mHandler.postDelayed(mRunnable, mSampleDurationTime);`
2nd you can try to get "best location" described in one of my answers, see link here
hope it will help you,
I am experiencing difficulties reliably throttling the gps update rate on the fly. The following approach seems consistent with everything I read, and it will occasionally change the update rate once or twice (to, say, taking one GPS reading every four seconds) but after that it just stays at a rate and will no longer change.
private LocationManager _locationMgr;
private LocationListener _locationListener;
private int _secondsPerUpdate=-1;
// Constructor
public AshGps(Activity l_activity, int l_secondsPerUpdate)
{
_locationMgr = (LocationManager) l_activity.getSystemService(Context.LOCATION_SERVICE);
_locationListener = new mylocationlistener();
_locationMgr.requestLocationUpdates(LocationManager.GPS_PROVIDER, l_secondsPerUpdate*1000, 0, _locationListener);
_secondsPerUpdate = l_secondsPerUpdate;
}
// Called up to once every three seconds
// to change the update rate
void ChangeUpdateRate(int l_secondsPerUpdate )
{
if( _secondsPerUpdate != l_secondsPerUpdate )
{
_locationMgr.removeUpdates(_locationListener);
_locationMgr.requestLocationUpdates(LocationManager.GPS_PROVIDER, l_secondsPerUpdate*1000, 0, _locationListener);
_secondsPerUpdate = l_secondsPerUpdate;
}
}
// Methods handles the incoming GPS reading 'event'
private class mylocationlistener implements LocationListener
{
#Override
public void onLocationChanged(Location location)
{
...
The time period per update is a suggestion to Android. It will not always be honored. Quoting the documentation:
This field is only used as a hint to conserve power, and actual time between location updates may be greater or lesser than this value.
my app need use new current GPS parameter(update after each from 3 to 8 second): latitude and longitude. and i am using both: GPS-provider and Network-provider.
i know use to update the GPS parameters
if(gps_enabled)
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListenerGps);
if(network_enabled)
lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListenerNetwork);
The Problem: in fact, the gps update after each environ 40-50 second
How can i get the GPS update after 3-8 seconds ??
thanks you
try{gps_enabled=lm.isProviderEnabled(LocationManager.GPS_PROVIDER);}catch(Exception ex){}
try{network_enabled=lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);}catch(Exception ex){}
//lm is locationManager
In fact. i don't use the condition: network_enabled or Network-provider to get Location. ---> It work and the new code:
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 2000, 0, locationListenerGps);
The reason, i don't use the Network_Provider. Because, when 2 GPS and Network Provider, system will use the NEtwork_provider. But in the logcat, i see that Smartphone does not update"Listenter" loop 3-6s with Network_provider.
En revanche, with GPS_PROVIDER, smartphone update alway 3-6s.
-- First time when open GPS; i need 30-50second to have the first Listener. But it is OK
I've written a little app that will return position, average speed and current speed. When I run it on my phone (HTC Legend) it updates 1-2 times a second. You're more than welcome to use it if you like. you just need to create a main.xml file with 6 textviews and then add this line to your AndroidManifest.xmll file:
package Hartford.gps;
import java.math.BigDecimal;
import android.app.Activity;
import android.content.Context;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.widget.TextView;
public class GPSMain extends Activity implements LocationListener {
LocationManager locationManager;
LocationListener locationListener;
//text views to display latitude and longitude
TextView latituteField;
TextView longitudeField;
TextView currentSpeedField;
TextView kmphSpeedField;
TextView avgSpeedField;
TextView avgKmphField;
//objects to store positional information
protected double lat;
protected double lon;
//objects to store values for current and average speed
protected double currentSpeed;
protected double kmphSpeed;
protected double avgSpeed;
protected double avgKmph;
protected double totalSpeed;
protected double totalKmph;
//counter that is incremented every time a new position is received, used to calculate average speed
int counter = 0;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
run();
}
#Override
public void onResume() {
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 1, this);
super.onResume();
}
#Override
public void onPause() {
locationManager.removeUpdates(this);
super.onPause();
}
private void run(){
final Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
criteria.setSpeedRequired(true);
criteria.setAltitudeRequired(false);
criteria.setBearingRequired(false);
criteria.setCostAllowed(true);
criteria.setPowerRequirement(Criteria.POWER_LOW);
//Acquire a reference to the system Location Manager
locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
// Define a listener that responds to location updates
locationListener = new LocationListener() {
public void onLocationChanged(Location newLocation) {
counter++;
//current speed fo the gps device
currentSpeed = round(newLocation.getSpeed(),3,BigDecimal.ROUND_HALF_UP);
kmphSpeed = round((currentSpeed*3.6),3,BigDecimal.ROUND_HALF_UP);
//all speeds added together
totalSpeed = totalSpeed + currentSpeed;
totalKmph = totalKmph + kmphSpeed;
//calculates average speed
avgSpeed = round(totalSpeed/counter,3,BigDecimal.ROUND_HALF_UP);
avgKmph = round(totalKmph/counter,3,BigDecimal.ROUND_HALF_UP);
//gets position
lat = round(((double) (newLocation.getLatitude())),3,BigDecimal.ROUND_HALF_UP);
lon = round(((double) (newLocation.getLongitude())),3,BigDecimal.ROUND_HALF_UP);
latituteField = (TextView) findViewById(R.id.lat);
longitudeField = (TextView) findViewById(R.id.lon);
currentSpeedField = (TextView) findViewById(R.id.speed);
kmphSpeedField = (TextView) findViewById(R.id.kmph);
avgSpeedField = (TextView) findViewById(R.id.avgspeed);
avgKmphField = (TextView) findViewById(R.id.avgkmph);
latituteField.setText("Current Latitude: "+String.valueOf(lat));
longitudeField.setText("Current Longitude: "+String.valueOf(lon));
currentSpeedField.setText("Current Speed (m/s): "+String.valueOf(currentSpeed));
kmphSpeedField.setText("Cuttent Speed (kmph): "+String.valueOf(kmphSpeed));
avgSpeedField.setText("Average Speed (m/s): "+String.valueOf(avgSpeed));
avgKmphField.setText("Average Speed (kmph): "+String.valueOf(avgKmph));
}
//not entirely sure what these do yet
public void onStatusChanged(String provider, int status, Bundle extras) {}
public void onProviderEnabled(String provider) {}
public void onProviderDisabled(String provider) {}
};
// Register the listener with the Location Manager to receive location updates
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 1, locationListener);
}
//Method to round the doubles to a max of 3 decimal places
public static double round(double unrounded, int precision, int roundingMode)
{
BigDecimal bd = new BigDecimal(unrounded);
BigDecimal rounded = bd.setScale(precision, roundingMode);
return rounded.doubleValue();
}
#Override
public void onLocationChanged(Location location) {
// TODO Auto-generated method stub
}
#Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
}
The minTime parameter of requestLocationUpdates should be 3000 to 8000
public void requestLocationUpdates (String provider, long minTime, float minDistance, LocationListener listener, Looper looper)
minTime the minimum time interval for notifications, in milliseconds. This field is only used as a hint to conserve power, and actual time between location updates may be greater or lesser than this value.
minDistance the minimum distance interval for notifications, in meters
Take a look at requestLocationUpdates(...)
public void requestLocationUpdates (String provider, long minTime, float minDistance, LocationListener listener)
Since: API Level 1
Registers the current activity to be notified periodically by the named provider. Periodically, the supplied LocationListener will be called with the current Location or with status updates.
It may take a while to receive the most recent location. If an immediate location is required, applications may use the getLastKnownLocation(String) method.
In case the provider is disabled by the user, updates will stop, and the onProviderDisabled(String) method will be called. As soon as the provider is enabled again, the onProviderEnabled(String) method will be called and location updates will start again.
The frequency of notification may be controlled using the minTime and minDistance parameters. If minTime is greater than 0, the LocationManager could potentially rest for minTime milliseconds between location updates to conserve power. If minDistance is greater than 0, a location will only be broadcasted if the device moves by minDistance meters. To obtain notifications as frequently as possible, set both parameters to 0.
Background services should be careful about setting a sufficiently high minTime so that the device doesn't consume too much power by keeping the GPS or wireless radios on all the time. In particular, values under 60000ms are not recommended.
The calling thread must be a Looper thread such as the main thread of the calling Activity.
Parameters
provider the name of the provider with which to register
minTime the minimum time interval for notifications, in milliseconds. This field is only used as a hint to conserve power, and actual time between location updates may be greater or lesser than this value.
minDistance the minimum distance interval for notifications, in meters
listener a {#link LocationListener} whose onLocationChanged(Location) method will be called for each location update
I'm working on a HTC Legend and try to build my own gps logging app. Everything works as expected beside the fact, that I have a gap of 30 minutes in every track.
This gap where I do not get gps data is always around minutes 30 to 60 - so after 30 minutes of activity, I have no gps data for 30 minutes. And without doing anything (not even restarting the app), it starts collecting data again after this 30 minutes break.
Does anyone have an explanation for this? It's driving me crazy...
Forgot to mention that I collect data with the straight forward requestLocationUpdates stuff, but no issues here...
EDIT: Code sample as requested:
private LocationListener ll = new LocationListener(){
#Override
public void onLocationChanged(Location loc) {
}
#Override
public void onProviderDisabled(String arg0) {
}
#Override
public void onProviderEnabled(String arg0) {
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
};
And here's the corresponding NMEA listener because I will handle raw GPS data:
GpsStatus.NmeaListener nl = new GpsStatus.NmeaListener() {
#Override
public void onNmeaReceived(long timestamp, String nmea) {
/*
* Use patcher and matcher to find a proper GPRMC sentence and remove symbols at the end like \n, # etc.
*/
m = p.matcher(nmea);
Log.d(LocationLoggerApp.TAG, "Time for a break...");
//Notify activity that app is ready for upload
broadcastIntent.putExtra("LOG", "Got valid GPRMC sentence");
sendBroadcast(broadcastIntent);
}
};
And here we have the line from the onStart function where above stuff is "loaded":
/*
* Request location updates as workaround because the function addNmeaListner DOES NOT enable GPS on the phone!
*/
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, interval*1000, 0, ll);
lm.addNmeaListener(nl);
Regards,
Martin
Any chance of some code samples? My first suggestion is to check you've set your minTime and minDistance parameters correctly.
public void requestLocationUpdates (long minTime, float minDistance, Criteria criteria, PendingIntent intent)