I've made a running app and for that, I've made a Service class to update user location (removed unimportant code):
public class LocationService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener, ILocationConstants {
private static final String TAG = LocationService.class.getSimpleName();
protected GoogleApiClient mGoogleApiClient;
protected LocationRequest mLocationRequest;
private LocationData data;
@Override
public void onCreate() {
super.onCreate();
data = new LocationData();
startForeground();
}
private void startForeground() {
//BUIDLING A NOTIFICATION
startForeground(101, notification);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
data = Parcels.unwrap(intent.getParcelableExtra(LOCATION_MESSAGE));
buildGoogleApiClient();
mGoogleApiClient.connect();
if (mGoogleApiClient.isConnected()) {
startLocationUpdates();
}
return START_STICKY;
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
createLocationRequest();
}
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
protected void startLocationUpdates() {
try {
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
} catch (SecurityException ex) {
} catch (Exception e) {
}
}
private void sendUpdates() {
data.millisecondTime = SystemClock.uptimeMillis() - data.startTime;
data.updateTime = data.timeBuff + data.millisecondTime;
data.seconds = (int) (data.updateTime / 1000);
data.minutes = data.seconds / 60;
data.hours = data.minutes / 60;
data.minutes = data.minutes % 60;
data.seconds = data.seconds % 60;
data.milliSeconds = (int) (data.updateTime % 1000);
Intent locationIntent = new Intent();
locationIntent.setAction(LOACTION_ACTION);
locationIntent.putExtra(LOCATION_MESSAGE, Parcels.wrap(data));
LocalBroadcastManager.getInstance(this).sendBroadcast(locationIntent);
}
protected void stopLocationUpdates() {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
@Override
public void onDestroy() {
stopLocationUpdates();
mGoogleApiClient.disconnect();
super.onDestroy();
}
@Override
public void onConnected(Bundle connectionHint) throws SecurityException {
Log.i(TAG, "Connected to GoogleApiClient");
if (data.mLastLocation == null) {
data.mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
sendUpdates();
}
startLocationUpdates();
}
@Override
public void onLocationChanged(Location location) {
sendLocationChanged(location);
Log.d(TAG, "onLocationChanged: " + location.getLatitude() + ", " + location.getLongitude());
sendUpdates();
}
public void sendLocationChanged(Location location) {
//SEND DATA TO THE SERVER
}
@Override
public void onConnectionSuspended(int cause) {
mGoogleApiClient.connect();
}
@Override
public void onConnectionFailed(ConnectionResult result) {
Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = " + result.getErrorCode());
}
@Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
}
After each location update I'm also calculating elapsed time (I have to do this by adding, because user may pause the activity). The problem is when I'm running the app in my office time is exact (for example 35 minutes), but when I'm riding a bicycle time is too short (shows 15mins when actually about 30 minutes passed). For the time perpsective the only difference is that it's called more often (in office gps refreshes only each 10-20 seconds, but outside may be even each 2 seconds). The route and distance are fine - service is not killed or something like that. I'm also updating time in activity, but replacing it on each update with the broadcasted (by the service) time, but even removing this didn't fix the issue. Why is this happening?