Android 的 FusedLocationApi 没有激活 GPS 和 returns 非常旧的日期

Android's FusedLocationApi doesn't activate GPS and returns very old dates

我在一个应用程序中编写了一些逻辑,用于每 15 分钟对用户的位置进行采样。我只对获取用户位置样本感兴趣,而不是持续跟踪他。

在真实设备上进行测试(启用位置设置)后,我发现我只能在连接到 WiFi 时获取位置信息。但是当我没有连接时(比如,走在街上),FusedLocationApi.getLastLocation 函数 returns 连接到 WiFi 时采样的旧位置,并且从不激活 GPS 来尝试获取真实位置当前位置。

虽然我知道我可以过滤掉旧位置,但我不确定如何让 FusedLocationApi 激活 GPS(或至少 return 一个最新位置)。 另一个限制是我不想让 GPS 开启太久,以免耗尽用户的电池。

在下面的代码中,我连接到 GoogleApiClient 并尝试获取最后的已知位置。如果这是空的,我注册以从中获取位置更新,一旦我得到一个(或允许的等待时间过去),我就断开连接。

我已经测试了一整天,FusedLocationApi 保持 return 早上在 WiFi 中采样的相同旧位置。

/**
 * First function in the location collection chain.
 * This function is called from outside whenever a client wants to get the user's current location.
 */
public void GetCurrentLocation(Context context, final LocationCallbackable callback) {
    currentContext = context;

    // Create an instance of GoogleAPIClient.
    if (mGoogleApiClient == null) {
        mGoogleApiClient = new GoogleApiClient.Builder(context)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
    }

    // Add the given callback to the callback list. This will be used to return the location to whoever requested it.
    callbacks.add(callback);

    // Connect to GoogleApiClient. When connected, this will trigger onConnected and then we'll be able to request the user's location.
    mGoogleApiClient.connect();
}

@Override
public void onConnected(@Nullable Bundle bundle) {
    // Create a location request.
    LocationRequest locationRequest = createLocationRequest();

    // Check if we don't have permissions to get fine location.
    if (ActivityCompat.checkSelfPermission(currentContext, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        // If we no permissions were granted - call the given callback with null.
        runCallback(null);
        return;
    }

    // If we got here, we have permissions :)
    Location location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
    if (location != null) {
        // Disconnect from GoogleApiClient.
        disconnect();

        // Call the callback that the caller has supplied us with, with the location we have.
        runCallback(location);
    }
    // Location was null - that means the GoogleApiClient didn't have enough time to get the current location.
    else {
        // In that case we should check if location settings are valid, and if so register to locationUpdated.
        // If the settings are not valid, we will terminate.
        VerifyLocationSettingsAndContinue(locationRequest);
    }
}

/**
 * Verify if the device's settings are valid for location sampling.
 * If they are - register to get location updates and unregister once we got it.
 * If they are not - the sampling chain is terminated, returning null to the client.
 */
private void VerifyLocationSettingsAndContinue(final LocationRequest locationRequest) {
    LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(locationRequest);
    final LocationManager _this = this;

    // Make sure the user's settings are satisfied.
    PendingResult<LocationSettingsResult> result = LocationServices.SettingsApi.checkLocationSettings(mGoogleApiClient, builder.build());

    // Set a callback for the pending result.
    result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
        @Override
        public void onResult(LocationSettingsResult result) {
            final Status status = result.getStatus();
            switch (status.getStatusCode()) {
                case LocationSettingsStatusCodes.SUCCESS:
                case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
                    LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, locationRequest, _this);

                    // We can get stuck waiting for an update from FusedLocationApi.requestLocationUpdates.
                    // To solve this, we wait 10 seconds and terminate our self (if we haven't already finished).
                    new android.os.Handler().postDelayed(
                            new Runnable() {
                                public void run() {
                                    // Only try to stop the operation if we didn't get a location update.
                                    if (!isLocationUpdated) {
                                        stopLocationUpdatesAndDisconnect();
                                        runCallback(null);
                                    }
                                }
                            },
                            10000);
                    break;
                case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
                default:
                    // Location settings are not satisfied. Terminate the location sampling by calling the callback with null.
                    disconnect();
                    runCallback(null);
                    break;
            }
        }
    });
}

@Override
public void onLocationChanged(Location location) {
    isLocationUpdated = true;
    // We got our location sample - unregister ourselves from requesting location updates and disconnect.
    stopLocationUpdatesAndDisconnect();
    // Call the callback with the location we just got.
    runCallback(location);
}

private void stopLocationUpdatesAndDisconnect() {
    LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
    disconnect();
}

private LocationRequest createLocationRequest() {
    final LocationRequest locationRequest = new LocationRequest();
    locationRequest.setInterval(4000);
    locationRequest.setFastestInterval(1000);
    locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    // Set that we only want one update.
    locationRequest.setNumUpdates(1);
    // If we don't get an update, kill the request after 30 seconds.
    locationRequest.setExpirationDuration(30000);

    return locationRequest;
}

当您调用 getLastKnownLocation 时,您将获取上次取点时的最后已知位置,但不会取新点。

例如,如果您在设备上唯一记录的点是在纽约,而您旅行 3 天到洛杉矶,然后记录一个新点(通过您的 VerifyLocationSettingsAndContinue 功能),您的应用程序是唯一一个请求任何积分的应用程序,那么当您调用 getLastKnownLocation 时,无论您调用多少次,您都会从纽约获得 3 天前的积分。

为了获得新积分,您必须请求位置更新。