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 天前的积分。
为了获得新积分,您必须请求位置更新。
我在一个应用程序中编写了一些逻辑,用于每 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 天前的积分。
为了获得新积分,您必须请求位置更新。