LocationClient getLastLocation() return null
Currently the Fused Location Provider
will only maintain background location if at least one client is connected to it. Once the first client connects, it will immediately try to get a location. If your activity is the first client to connect and you call getLastLocation()
right away in onConnected()
, that might not be enough time for the first location to come in.
Play Location Services getLastLocation returns null
First
It's kind of bug on old Android devices.
Apparently the location APIs have different behavior on different Android versions (LocationManager has issues on Android >= 4.1, while Play Services has issues on Android 2.3), see here.
So what I ended up with is below:
Trying to retrieve last location by play services, if failed try with LocationManager.
Second
I would like to thank you all for your valuable suggestions, I get the hint to use the previous workaround from AndroidHacker's post so I think he is the one who deserve the bounty.
LocationClient getLastLocation() returning null
mLocationClient.getLastLocation();
might return null if you don't have any last location saved by the device. If you read its documentation, it says;
It returns the best most recent location currently available.
If a location is not available, which should happen very rarely, null will be returned
Also inside the onLocationChanged
method you might want to set the Location to the latest location, when your location gets changed.
@Override
public void onLocationChanged(final Location location) {
mCurrentLocation = location;
}
locationclient.getlastlocation() always returns null on emulator
What eventually worked for me was setting a location (I use Genymotion, so the "GPS widget" in the upper right corner), then starting Google Maps, and then running my app.
My guess is that my app wasn't actually setting the current location (which I thought connecting my locationClient would do automatically) - Google Maps checks and sets the location, so getLastLocation actually has something to return.
getLastLocation() return null after moving code
The flow should be:
- Add location permission in AndroidManifest.xml
- Check if user has given that permission, if yes, check location settings; and of not then first ask for permission
- If permission is granted and location settings are ON, then you should do what you want.
In your case, from the code you've shown, you are not checking location settings and just after requesting permission, you are trying to getLastLocation()
which should be inside of if
statement when permission is granted and when permission is granted in onRequestPermissionsResult()
EDIT:
Add/Change the following code:
1.
protected void createLocationRequest() {
if (mLocationRequest == null) {
mLocationRequest = new LocationRequest();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(10000);
mLocationRequest.setFastestInterval(5000);
}
}
2.
private void checkLocationSettings() {
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(mLocationRequest);
final Task<LocationSettingsResponse> result =
LocationServices.getSettingsClient(MapsActivity.this).checkLocationSettings(builder.build());
result.addOnCompleteListener(new OnCompleteListener<LocationSettingsResponse>() {
@Override
public void onComplete(@NonNull Task<LocationSettingsResponse> task) {
Log.e(TAG, "onComplete() called with: task = [" + task.isComplete() + "]");
// All location settings are satisfied. The client can initialize
// location requests here.
// ...
getLastKnownLocation(mFusedLocationClient);
}
});
result.addOnFailureListener(this, new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Log.e(TAG, "onFailure() called with: e = [" + e + "]");
if (e instanceof ResolvableApiException) {
// Location settings are not satisfied, but this can be fixed
// by showing the user a dialog.
try {
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
ResolvableApiException resolvable = (ResolvableApiException) e;
resolvable.startResolutionForResult(MapsActivity.this,
REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException sendEx) {
// Ignore the error.
}
}
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.e("MapsActivity", "onActivityResult() called with: requestCode = [" + requestCode + "], resultCode = [" + resultCode + "], data = [" + data + "]");
getLastKnownLocation(mFusedLocationClient);
}
public void getLastKnownLocation(FusedLocationProviderClient cl) {
// Get last location
mFusedLocationClient.getLastLocation()
.addOnSuccessListener(this, new OnSuccessListener<Location>() {
@Override
public void onSuccess(Location location) {
Log.e(TAG, "onSuccess() called with: location = [" + location + "]");
// Got last known location. In some rare situations this can be null.
if (location != null) {
longitude = location.getLongitude();
latitude = location.getLatitude();
Log.e("MapsActivity", "onSuccess() called with: location = [" + location + "]");
LatLng mCurrentLocation = new LatLng(latitude, longitude);
mMap.addMarker(new MarkerOptions().position(mCurrentLocation).title("Current position"));
mMap.moveCamera(CameraUpdateFactory.newLatLng(mCurrentLocation));
// Set zoom level
mMap.animateCamera(CameraUpdateFactory.zoomTo(19.0f));
Toast.makeText(getApplicationContext(), "value is " + latitude + "poi" + longitude, Toast.LENGTH_LONG).show();
}
}
});
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case MY_PERMISSION_FINE_LOCATION:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
mMap.setMyLocationEnabled(true);
createLocationRequest();
checkLocationSettings();
} else {
Toast.makeText(getApplicationContext(), "This app requires location permission to be granted", Toast.LENGTH_LONG).show();
finish();
}
break;
}
And only this code related to location in
onMapReady()
:// Check if localization permission is granted
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
== PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
mMap.setMyLocationEnabled(true);
createLocationRequest();
checkLocationSettings();
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
ActivityCompat.requestPermissions(this
, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}
, MY_PERMISSION_FINE_LOCATION);
}
}
Make sure you have both below permissions in manifest:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
FusedLocationApi.getLastLocation always null
The fused Location Provider
will only maintain background location if at least one client is connected to it. Now just turning on the location service will not guarantee to store the last known location.
Once the first client connects, it will immediately try to get a location. If your activity is the first client to connect and getLastLocation()
is invoked right away in onConnected()
, that might not be enough time for the first location to arrive..
I suggest you to launch the Maps app first, so that there is at least some confirmed location, and then test your app.
getLastLocation returns a null value
getLastLocation()
has a high tendency to return null. It also does not request a new location, so even if you get a location, it could be very old, and not reflect the current location. Better to register a listener, even if you just unregister after you get the first onLocationChanged() callback.
This question gets asked a lot, and usually is marked as a duplicate of questions like this one
However, in your case, it also looks like you just forgot to call connect()
:
buildGoogleApiClient();
mGoogleApiClient.connect(); //added
You can use the code in this answer as a reference for registering for location callbacks, which is suggested if you want to get an accurate current location.
Edit: Since you need only one location, here is a slightly modified version of that code, which requests location updates, and then un-registers for location updates after the first location comes in.
public class MainActivity extends Activity implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener {
LocationRequest mLocationRequest;
GoogleApiClient mGoogleApiClient;
private Location mLastLocation;
private double mLatitude;
private double mLongitude;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
buildGoogleApiClient();
mGoogleApiClient.connect();
}
@Override
protected void onPause(){
super.onPause();
if (mGoogleApiClient != null) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
@Override
public void onConnected(Bundle bundle) {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(1000);
mLocationRequest.setFastestInterval(1000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
//mLocationRequest.setSmallestDisplacement(0.1F);
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
@Override
public void onConnectionSuspended(int i) {
Toast.makeText(this,"onConnectionSuspended",Toast.LENGTH_SHORT).show();
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Toast.makeText(this,"onConnectionFailed",Toast.LENGTH_SHORT).show();
}
@Override
public void onLocationChanged(Location location) {
mLastLocation = location;
//no need to do a null check here:
mLatitude = location.getLatitude();
mLongitude = location.getLongitude();
//remove location updates if you just need one location:
if (mGoogleApiClient != null) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
}
}
Related Topics
Passing Arraylist Through Intent
What Characters Allowed in File Names on Android
Actionbar Not Shown with Appcompat
How to Set a Gradient Background in a Material Button from Material Components
Streaming Video from Android Camera to Server
How to Create a Circular Progressbar in Android Which Rotates on It
Border for an Image View in Android
Enabling Proguard in Eclipse for Android
Best Practice: Asynctask During Orientation Change
In Android, How to Set Margins in Dp Programmatically
Get Content Uri from File Path in Android
Android Studio Gradle Build Speed Up
Create Aar File in Android Studio
Android Backup/Restore: How to Backup an Internal Database
How to Create Custom Button in Android Using Xml Styles