问题
When I enter a screen, I check for if GPS is turned on, if not, the dialog to enable GPS is shown. When user clicks Yes, onActivityResult -> GPS is turned on and I try to get the location but this always returns null
When I enter the screen with GPS already on, location is retrieved properly. I have been struggling with this for few days now and can't seem to find any resources.
UserLocationUtilities.java
public class UserLocationUtilities implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener{
GoogleApiClient googleApiClient;
Activity activity;
protected static final int REQUEST_CHECK_SETTINGS = 0x1;
boolean isGPSEnabled = false;
// flag for network status
boolean isNetworkEnabled = false;
// flag for GPS status
boolean canGetLocation = false;
protected LocationManager locationManager;
protected LocationListener locationListener;
protected Location location;
protected double latitude,longitude;
protected boolean gps_enabled,network_enabled;
// The minimum distance to change Updates in meters
private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // 10 meters
// The minimum time between updates in milliseconds
private static final long MIN_TIME_BW_UPDATES = 1 * 1000 * 60; // 1 minute
public UserLocationUtilities(Activity activity){
this.activity = activity;
}
public void settingsRequest()
{
if(googleApiClient == null){
googleApiClient = new GoogleApiClient.Builder(activity)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).build();
googleApiClient.connect();
}
LocationRequest locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(30 * 1000);
locationRequest.setFastestInterval(5 * 1000);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(locationRequest);
builder.setAlwaysShow(true); //this is the key ingredient
PendingResult<LocationSettingsResult> result = LocationServices.SettingsApi.checkLocationSettings(googleApiClient, builder.build());
result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
@Override
public void onResult(LocationSettingsResult result) {
final Status status = result.getStatus();
final LocationSettingsStates state = result.getLocationSettingsStates();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS:
// All location settings are satisfied. The client can initialize location
// requests here.
break;
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
// Location settings are not satisfied. But could be fixed by showing the user
// a dialog.
try {
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
status.startResolutionForResult(activity, REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException e) {
// Ignore the error.
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
// Location settings are not satisfied. However, we have no way to fix the
// settings so we won't show the dialog.
break;
}
}
});
}
public Location getLocation() {
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
try {
locationManager = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE);
isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if (!isGPSEnabled && !isNetworkEnabled) {
// no network provider is enabled
} else {
this.canGetLocation = true;
if (isNetworkEnabled) {
locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER,
MIN_TIME_BW_UPDATES,
MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
Log.d("Network", "Network");
if (locationManager != null) {
location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if (location != null) {
latitude = location.getLatitude();
longitude = location.getLongitude();
}
}
}
// if GPS Enabled get lat/long using GPS Services
if (isGPSEnabled) {
if (location == null) {
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
MIN_TIME_BW_UPDATES,
MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
Log.d("GPS Enabled", "GPS Enabled");
if (locationManager != null) {
location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (location != null) {
latitude = location.getLatitude();
longitude = location.getLongitude();
}
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
return location;
}
public boolean isLocationEnabled() {
int locationMode = 0;
String locationProviders;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
try {
locationMode = Settings.Secure.getInt(activity.getApplicationContext().getContentResolver(), Settings.Secure.LOCATION_MODE);
} catch (Settings.SettingNotFoundException e) {
e.printStackTrace();
}
return locationMode != Settings.Secure.LOCATION_MODE_OFF;
}else{
locationProviders = Settings.Secure.getString(activity.getApplicationContext().getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
return !TextUtils.isEmpty(locationProviders);
}
}
@Override
public void onConnected(Bundle bundle) {
}
@Override
public void onConnectionSuspended(int i) {
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
@Override
public void onLocationChanged(Location location) {
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
}
After user selects Yes in Settings Dialog, onActivityResult, I do location = userlocationutilities.getLocation(); and always returns null. If switch screens and come back, location is retrieved.
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
// Check for the integer request code originally supplied to startResolutionForResult().
case REQUEST_CHECK_SETTINGS:
switch (resultCode) {
case Activity.RESULT_OK: //location settings dialog, user selected YES to enabling location
location = userLocationUtilities.getLocation();
if(location != null){
//location of user FOUND
Toast.makeText(getActivity(), "Lat: "+location.getLatitude()+" Long: "+location.getLongitude(), Toast.LENGTH_LONG).show();
getRingsNearMeCall();
}else{
//location of user NOT FOUND
Toast.makeText(getActivity(), "null location", Toast.LENGTH_LONG).show();
}
break;
case Activity.RESULT_CANCELED: //location settings dialog, user selected NO to enabling location
userLocationUtilities.settingsRequest(); //ask user again with Location Settings Dialog
break;
}
break;
}
}
Editted: I make the requestPermission in the fragment, the permission is granted
if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(getActivity(), new String[] { Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION },
PERMISSION_ACCESS_FINE_LOCATION);
}else{
checkLocationSettingsGetRings();
}
回答1:
LocationSettingsRequest is used just make location settings adequate, for example you want receive more accurate (HIGH_ACCURACY) locations, then you need GPS is enabled. So in that case, LocationSettingsRequest prompts the dialog to allow api change settings.
After pressing OK, you can see that GPS is enabled. But it does not mean you are granted to make location request yet.
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_CHECK_SETTINGS:
switch (resultCode) {
case Activity.RESULT_OK:
// Here means required settings are adequate.
// We can make location request.
// But are we granted to use request location updates ?
break;
}
break;
}
}
}
Thats okay, but you are checking the permission, but you did never make requestPermissions. This is the first possible reason of getting null.
public Location getLocation() {
if (ContextCompat.checkSelfPermission(activity,
Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
...
}
return location;
}
Even you are previously granted to make location request
location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
getLastKnownLocation() method could return null, this is not unexpected behaviour. This is the second possible reason of getting null
You are making location request, but the global location variable is never assigned in onLocationChanged callback.
@Override
public void onLocationChanged(Location location) {
// global location variable is not assigned ?
// getLocation() method will return null if getLastKnownLocation()
// did not return null previously.
}
This is third possible reason of getting null.
回答2:
Finally, I find a solution: I create a thread and wait for my location available.
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode){
case REQUEST_LOCATION:
switch (resultCode){
case Activity.RESULT_OK:
mHandler = new Handler();
runnable = new Runnable() {
@Override
public void run() {
mHandler.postDelayed(this,1000);
checkLocationAvailable();
}
};
mHandler.postDelayed(runnable,1000);
break;
case Activity.RESULT_CANCELED:
break;
}
}
}
Create a function to stop the thread when my location available.
private void checkLocationAvailable(){
if (mMap.getMyLocation() != null) {
mHandler.removeCallbacks(runnable);
// do stuff
}
}
It is not a good solution, but hope it will help.
回答3:
Add this override method for me its worked fine--
@Override
public void onLocationChanged(Location location) {
getLocation("onLocationChanged");
}
来源:https://stackoverflow.com/questions/37557361/android-location-return-null-after-enabling-gps-in-dialog