I am experiencing some strange behaviour from monitoring the times of updated locations from the GPS LocationListener.
Sometimes (though intermittently) I will see the updated location have a timestamp a fraction of a second off (despite the minimum update being set to 5000milliseconds in requestUpdates) or sometimes even earlier than the previous location?
Example of both seen as fraction of a second before previous location (logcat output, edited for clarity):
GpsTracker_v4: onLocationChanged: Warning: location update is older than previous location
D/GpsTracker_v4:
previous location:
provider: network
time:20/02/22 06:07:17.468
---
new location:
provider: network
time: 20/02/22 06:07:17.467
I have logged enough by now to (fairly) confidently claim this is not due to a gps/network provider conflict, or due to it only being milliseconds apart (example of longer durations up to seconds long included at bottom of post)
My entire tracker class (minus the dozens of debugging logs):
public class GpsTracker_v4 {
/*--------------------------------------
CONSTANTS
--------------------------------------*/
private static final String TAG = GpsTracker_v4.class.getSimpleName();
// location updates interval - 5sec
private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 5000;
/*--------------------------------------
MEMBER VARIABLES
--------------------------------------*/
//---VARIABLES---
Context context;
LocationManager locationManager;
LocationListener locationListener;
Location previousLocation = null;
/*--------------------------------------
CONSTRUCTOR
--------------------------------------*/
//-create manager and initialise location listener
public GpsTracker_v4(Context c) {
this.context = c;
locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
locationListener = new LocationListener() {
@Override
public void onLocationChanged(Location location) {
if (location != null) {
if (previousLocation != null) {
//check location update is more recent than previous
if (checkUpdateTime(location)) {
Log.d(TAG, "onLocationChanged: new location more recent");
} else {
Log.w(TAG, "onLocationChanged: Warning: location update is " +
"older than previous location");
}
Log.d(TAG, "previous location:\n" +
"provider: " + previousLocation.getProvider() + "\n" +
"time:" + getDateString(previousLocation.getTime()) + "\n" +
"---\n" +
"new location:\n" +
"provider: " + location.getProvider() + "\n" +
"time: " + getDateString(location.getTime()));
//check location is more accurate than previous location
if (checkUpdateAccuracy(location)) {
Log.d(TAG, "onLocationChanged: location update is more accurate");
} else {
Log.w(TAG, "onLocationChanged: Warning: location update is " +
"less accurate or equal to previous");
}
Log.d(TAG, "Prev location:\n" +
"provider: " + previousLocation.getProvider() + "\n" +
"accuracy: " + previousLocation.getAccuracy() + "\n" +
"---\n" +
"New location:\n" +
"provider: " + location.getProvider() + "\n" +
"accuracy: " + location.getAccuracy());
} else {
//no previous location yet
Log.d(TAG, "onLocationChanged: previousLocation is null: " +
"using first location update:");
}
//replace previous location with updated
previousLocation = location;
//debugging attempt: remove all content of location
location = null;
} else {
//null location passed
Log.e(TAG, "onLocationChanged: Error: passed location is NULL");
//todo: handle
}
}
@Override
public void onStatusChanged(String s, int i, Bundle bundle) {
//todo:
}
@Override
public void onProviderEnabled(String s) {
//todo:
}
@Override
public void onProviderDisabled(String s) {
//todo:
}
};
beginRequestUpdates();
}
/*--------------------------------------
METHODS
--------------------------------------*/
//-begin requesting updates from both gps and network providers
public void beginRequestUpdates() {
//permission check (IDE insists its done here, not earlier or in another method)
if (ContextCompat.checkSelfPermission(context,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ContextCompat.checkSelfPermission(
context, Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
Log.e(TAG, "checkPermission: Error: Permission not been granted.);
return;
}
//begin GPs updates
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
UPDATE_INTERVAL_IN_MILLISECONDS,
0,
locationListener,
Looper.getMainLooper());
Log.d(TAG, "beginRequestUpdates: GPS updates requested");
//begin network updates
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
UPDATE_INTERVAL_IN_MILLISECONDS,
0,
locationListener,
Looper.getMainLooper());
Log.d(TAG, "beginRequestUpdates: Network updates requested");
}
/*--------------------------------------
HELPER METHODS
--------------------------------------*/
//-return true if time of location update is more recent than previous update time
public boolean checkUpdateTime(Location location) {
return location.getTime() > previousLocation.getTime();
}
//-return true if location update is more accurate than previous location
public boolean checkUpdateAccuracy(Location location) {
return location.getAccuracy() < previousLocation.getAccuracy();
}
//-get user-readable date/time from milli (in year-month-day format)
private String getDateString(long milliSeconds) {
String dateFormat = "yy/MM/dd hh:mm:ss.SSS";
SimpleDateFormat formatter = new SimpleDateFormat(dateFormat);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(milliSeconds);
return formatter.format(calendar.getTime());
}
public void printLocation(Location location) {
System.out.println("" +
"Provider: " + location.getProvider() + "\n" +
"Latitude: " + location.getLatitude() + "\n" +
"Longitude: " + location.getLongitude() + "\n" +
"Accuracy: " + location.getAccuracy() + "\n" +
"Time: " + getDateString(location.getTime()) + "\n");
}
/*--------------------------------------
MUTATORS
--------------------------------------*/
//-set listener from outside class
public void setListener(LocationListener listener) {
this.locationListener = listener;
}
}
What is the reason for this behaviour?
Edit
Here is a better example of new location update being timestamped prior to previous:
updated location:
Time: 20/02/22 06:44:57.346
previous location:
Time: 20/02/22 06:45:21.370