我刚刚切换到使用新的FusedLocationProviderClient
而不是旧的FusedLocationProviderApi
。
以下代码几乎适用于所有设备。但是,在某些三星手机上,它偶尔会做一些奇怪的事情:Google Play服务会调用onLocationResult
,但不提供LocationResult
个对象。据我了解文档,这应该不会发生,因为onLocationResult
的重点是它只在有位置更新时触发,为什么我会获得null
个位置?为什么只在某些设备上?
public class ButtonActivity extends AppCompatActivity {
// ...
// An instance of my listener inner class
private LocationProcessor locationProcessor;
private FusedLocationProviderClient fusedLocationClient;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ...
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
locationProcessor = new LocationProcessor();
}
@Override
protected void onResume() {
// ...
locationProcessor.enable();
super.onResume();
}
private class LocationProcessor extends LocationCallback {
// SettableBoolean is something simple we wrote to be able to synchronize on a boolean
private final SettableBoolean isEnabled = new SettableBoolean(false);
private void disable() {
if (fusedLocationClient != null) {
fusedLocationClient.removeLocationUpdates(this);
}
synchronized (isEnabled) {
isEnabled.setBoolean(false);
}
}
private void enable() {
if (ActivityCompat.checkSelfPermission(ButtonActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(ButtonActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(ButtonActivity.this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, MY_PERMISSIONS_REQUEST_FINE_LOCATION);
return;
}
synchronized (isEnabled) {
if (isEnabled.getBoolean()) {
return;
}
isEnabled.setBoolean(true);
}
// Check if we already know about a location before we start listening for updates.
Task<Location> locationTask = fusedLocationClient.getLastLocation();
Location lastLocation = locationTask.isSuccessful() ? locationTask.getResult() : null;
if (lastLocation != null) {
long locationAcceptableAge_s = (long) getResources().getInteger(R.integer.location_acceptable_age_s);
long locationAge = locationAgeInSeconds(lastLocation);
if (locationAge <= locationAcceptableAge_s) {
User.setCurrentLocation(lastLocation);
}
} else {
Log.w(TAG, "no location at onConnected");
}
long locationInterval_ms = (long) getResources().getInteger(R.integer.location_interval_active_ms);
long fastestLocationInterval_ms = (long) getResources().getInteger(R.integer.fastest_location_interval_ms);
int locationResolution = getResources().getInteger(R.integer.location_resolution_m);
LocationRequest locationRequest = LocationRequest.create()
.setInterval(locationInterval_ms)
.setFastestInterval(fastestLocationInterval_ms)
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setSmallestDisplacement(locationResolution);
fusedLocationClient.requestLocationUpdates(locationRequest, this, null);
}
@Override
public void onLocationResult(LocationResult locationResult) {
// The only place this is ever a problem is on some Samsung devices. Everyone else ALWAYS has
// a `lastLocation` to be gotten.
if (locationResult == null) {
Log.d(TAG, "onLocationChanged: NO LOCATION FOUND");
// This displays a dialog to the user that we cannot determine their location
resetInterface(getString(R.string.no_location_api));
return;
}
Location location = locationResult.getLastLocation();
Log.d(TAG, "onLocationChanged: " + location.getProvider());
User.setCurrentLocation(location);
}
@Override
public void onLocationAvailability(LocationAvailability locationAvailability) {
if (locationAvailability.isLocationAvailable()) {
enable();
} else {
String noLocationAPI = getString(R.string.no_location_api);
resetInterface(noLocationAPI);
}
}
}
}