在后台服务中计算时间

Counting time in background service

我制作了一个 运行 应用程序,为此,我制作了一个服务 class 来更新用户位置(删除了不重要的代码):

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");
    }

}

每次位置更新后,我还会计算经过的时间(我必须通过添加来执行此操作,因为用户可能会暂停 activity)。问题是当我 运行 时,应用程序在我办公室的时间是准确的(例如 35 分钟),但是当我骑自行车时时间太短(显示 15 分钟,而实际上已经过去了大约 30 分钟)。从时间的角度来看,唯一的区别是它被调用得更频繁(在办公室 gps 仅每 10-20 秒刷新一次,但在外面甚至可能每 2 秒刷新一次)。路线和距离都很好 - 服务不会被杀死或类似的东西。我也在 activity 中更新时间,但在每次更新时将其替换为广播的(由服务)时间,但即使删除它也不能解决问题。为什么会这样?

SystemClock documentation

所述

uptimeMillis() is counted in milliseconds since the system was booted. This clock stops when the system enters deep sleep (CPU off, display dark, device waiting for external input)

所以这可能是您获得不同时间的原因。另一方面,有 elapsedRealtime()elapsedRealtimeNanos() 方法,其中

return the time since the system was booted, and include deep sleep. This clock is guaranteed to be monotonic, and continues to tick even when the CPU is in power saving modes, so is the recommend basis for general purpose interval timing

尝试使用其中之一。

我建议在 onLocationChanged() 中使用每次位置更新获得的时间,并将其传递给 sendUpdates() 方法

void onLocationChanged(Location location){

    long currentTime=location.getTime(); // unix time in milliseconds

    .......

    sendUpdates(currentTime);

}

然后在 sendUpdates(long currentTime) 中进行时间计算。如果我理解正确的话,您只对应用程序启动后经过的时间感兴趣。在那种情况下,我猜你可以通过只使用 data.startTime、data.seconds、data.minutes 和 data.hours 来简化你的 data 对象时间。您可以在应用程序启动后从第一次修复的位置获取开始时间(利用标志或类似检测第一次修复)。

然后在 sendUpdates(long currentTime) 中,我会像这样计算经过时间的秒、分钟、小时:

int elapsedSeconds=int((currentTime-data.StartTime)/1000);
data.hours=int(elapsedSeconds/3600);
data.minutes=int(elapsedSeconds/60)-60*data.hours;
data.seconds=elapsedSeconds-60*(data.minutes+60*data.hours);