I am trying to get location by using FusedLocationApi.getLastLocation
and I've got the location permissions in the manifest file:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
However, I am getting null
when I request the location from the system. I was just testing turning off and on location services so it may be related to that (of course, it's ON when I'm trying this). But even after returning null, I'm waiting for onLocationChanged
to be called and it's never called. I've also seen a similar question here: FusedLocationApi.getLastLocation always null
Here is my code:
protected LocationRequest createLocationRequest() { LocationRequest mLocationRequest = new LocationRequest(); mLocationRequest.setInterval(120000); mLocationRequest.setFastestInterval(30000); mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY); return mLocationRequest; } protected GoogleApiClient getLocationApiClient(){ return new GoogleApiClient.Builder(this) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .addApi(LocationServices.API) .build(); } LocationRequest locationRequest = createLocationRequest(); @Override public void onLocationChanged(Location location) { App.setLocation(location); // NEVER CALLED } @Override public void onConnected(Bundle bundle) { App.setLocation(LocationServices.FusedLocationApi.getLastLocation(locationApiClient)); //RETURNS NULL LocationRequest locationRequest = createLocationRequest(); LocationServices.FusedLocationApi.requestLocationUpdates(locationApiClient, locationRequest, this); }
And on onCreate
of my app:
locationApiClient = getLocationApiClient(); locationApiClient.connect();
Where this
is my application object. Why am I getting null (yes, I do know it may be null in some rare circumstances as stated in the documents, but I'm ALWAYS getting this, not rarely) and still not getting location updates thereafter? It's a real device (Samsung Galaxy S3) without a SIM card, if it helps.
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 storing 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..
Then you are setting mLocationRequest.setFastestInterval(30000);
which basically means 30 seconds. so at least 30 seconds after and generally according to your setting preferred time is 120 secs, isn't it a very long time if there is no stored last known location at all? plus you are setting battery balanced priority, which will make you waiting longer time.
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
I suggest you to launch Maps app first, so that there is at least some confirmed location and then test your app.
1I am using FusedLocationProvider api in my app, Here is my code that works both on device and emulator -
@Override protected void onCreate(Bundle savedInstanceState){ //put your code here .... getLocation(); } private void getLocation(){ locationRequest = LocationRequest.create(); locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); locationRequest.setInterval(LOCATION_INTERVAL); locationRequest.setFastestInterval(LOCATION_INTERVAL); fusedLocationProviderApi = LocationServices.FusedLocationApi; googleApiClient = new GoogleApiClient.Builder(this) .addApi(LocationServices.API) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .build(); if (googleApiClient != null) { googleApiClient.connect(); } } @Override public void onConnected(Bundle arg0) { fusedLocationProviderApi.requestLocationUpdates(googleApiClient, locationRequest, this); } @Override public void onLocationChanged(Location location) { Toast.makeText(mContext, "location :"+location.getLatitude()+" , "+location.getLongitude(), Toast.LENGTH_SHORT).show(); }
this is working code of mine.
Hope my code help you.
Cheers..
4If it returns null, this means you need start receiving location updates with LocationServices.FusedLocationApi.requestLocationUpdates before retrieving the location.
For me, a solution to the problem was to call the:
LocationServices.FusedLocationApi.requestLocationUpdates(locationApiClient,locationRequest, this);
before the:
App.setLocation(LocationServices.FusedLocationApi.getLastLocation(locationApiClient));
The problem is that the last location does not exist so it was null.
If the problem persist try this:
Check the necessary permissions.
Ensure you've enabled position on your device, then restart.
1I have used FusedAPI and Below code is working for me... Test in Real device
import android.Manifest; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.IntentSender; import android.content.pm.PackageManager; import android.location.Location; import android.location.LocationManager; import android.os.AsyncTask; import android.os.Bundle; import android.os.Looper; import android.provider.Settings; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.ActivityCompat; import android.support.v4.app.FragmentActivity; import android.support.v4.content.PermissionChecker; import android.widget.ProgressBar; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GoogleApiAvailability; import com.google.android.gms.common.api.ApiException; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.common.api.ResolvableApiException; import com.google.android.gms.common.api.ResultCallback; import com.google.android.gms.location.FusedLocationProviderClient; import com.google.android.gms.location.LocationCallback; import com.google.android.gms.location.LocationListener; import com.google.android.gms.location.LocationRequest; import com.google.android.gms.location.LocationResult; import com.google.android.gms.location.LocationServices; import com.google.android.gms.location.LocationSettingsRequest; import com.google.android.gms.location.LocationSettingsResponse; import com.google.android.gms.location.LocationSettingsResult; import com.google.android.gms.location.LocationSettingsStatusCodes; import com.google.android.gms.location.SettingsClient; import com.google.android.gms.maps.CameraUpdate; import com.google.android.gms.maps.CameraUpdateFactory; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.OnMapReadyCallback; import com.google.android.gms.maps.SupportMapFragment; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.LatLngBounds; import com.google.android.gms.maps.model.Marker; import com.google.android.gms.maps.model.MarkerOptions; import com.google.android.gms.tasks.OnCanceledListener; import com.google.android.gms.tasks.OnFailureListener; import com.google.android.gms.tasks.OnSuccessListener; import java.util.ArrayList; import java.util.LinkedHashMap; public class MapsActivity extends FragmentActivity implements OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener, ResultCallback<LocationSettingsResult> { private static final int REQUEST_CHECK_SETTINGS = 214; private static final int REQUEST_ENABLE_GPS = 516; private final int REQUEST_LOCATION_PERMISSION = 214; protected GoogleApiClient mGoogleApiClient; protected LocationSettingsRequest mLocationSettingsRequest; /* For Google Fused API */ private FusedLocationProviderClient mFusedLocationClient; private SettingsClient mSettingsClient; private LocationCallback mLocationCallback; private LocationRequest mLocationRequest; private Location mCurrentLocation; /* For Google Fused API */ private Context context; private ProgressBar progressBar; private AsyncTask task; private GoogleMap mMap; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_maps); SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager() .findFragmentById(R.id.map); mapFragment.getMapAsync(this); try { int permissionCheck = PermissionChecker.checkCallingOrSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION); if (permissionCheck == PackageManager.PERMISSION_GRANTED) { Helper.showLog("Permission is already allowed. Build Client"); buildGoogleApiClient(); } else { Helper.showLog("Permission is requested"); ActivityCompat.requestPermissions(MapsActivity.this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_LOCATION_PERMISSION); } } catch (Exception e) { e.printStackTrace(); } } @Override public void onMapReady(GoogleMap googleMap) { mMap = googleMap; // Add a marker in Sydney and move the camera LatLng sydney = new LatLng(-34, 151); mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney")); mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney)); } protected synchronized void buildGoogleApiClient() { mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this); mSettingsClient = LocationServices.getSettingsClient(this); mGoogleApiClient = new GoogleApiClient.Builder(this) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .addApi(LocationServices.API) .build(); connectGoogleClient(); mLocationCallback = new LocationCallback() { @Override public void onLocationResult(LocationResult locationResult) { super.onLocationResult(locationResult); Helper.showLog("Location Received"); mCurrentLocation = locationResult.getLastLocation(); onLocationChanged(mCurrentLocation); } }; } private void connectGoogleClient() { GoogleApiAvailability googleAPI = GoogleApiAvailability.getInstance(); int resultCode = googleAPI.isGooglePlayServicesAvailable(this); if (resultCode == ConnectionResult.SUCCESS) { mGoogleApiClient.connect(); } else { int REQUEST_GOOGLE_PLAY_SERVICE = 988; googleAPI.getErrorDialog(this, resultCode, REQUEST_GOOGLE_PLAY_SERVICE); } } @Override public void onConnected(@Nullable Bundle bundle) { mLocationRequest = new LocationRequest(); mLocationRequest.setInterval(30 * 1000); mLocationRequest.setFastestInterval(5 * 1000); mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder(); builder.addLocationRequest(mLocationRequest); builder.setAlwaysShow(true); mLocationSettingsRequest = builder.build(); mSettingsClient .checkLocationSettings(mLocationSettingsRequest) .addOnSuccessListener(new OnSuccessListener<LocationSettingsResponse>() { @Override public void onSuccess(LocationSettingsResponse locationSettingsResponse) { Helper.showLog("GPS Success"); requestLocationUpdate(); } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { int statusCode = ((ApiException) e).getStatusCode(); switch (statusCode) { case LocationSettingsStatusCodes.RESOLUTION_REQUIRED: try { ResolvableApiException rae = (ResolvableApiException) e; rae.startResolutionForResult(MapsActivity.this, REQUEST_CHECK_SETTINGS); } catch (IntentSender.SendIntentException sie) { Helper.showLog("PendingIntent unable to execute request."); } break; case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE: Helper.showLog("Location settings are inadequate, and cannot be fixed here. Fix in Settings."); } } }).addOnCanceledListener(new OnCanceledListener() { @Override public void onCanceled() { Helper.showLog("checkLocationSettings -> onCanceled"); } }); } @Override public void onConnectionSuspended(int i) { connectGoogleClient(); } @Override public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { buildGoogleApiClient(); } @Override public void onResult(@NonNull LocationSettingsResult locationSettingsResult) { } @Override public void onLocationChanged(Location location) { String latitude = String.valueOf(location.getLatitude()); String longitude = String.valueOf(location.getLongitude()); if (latitude.equalsIgnoreCase("0.0") && longitude.equalsIgnoreCase("0.0")) { requestLocationUpdate(); } else { //Perform Your Task with LatLong } } @SuppressLint("MissingPermission") private void requestLocationUpdate() { mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper()); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_CHECK_SETTINGS) { switch (resultCode) { case Activity.RESULT_OK: Helper.showLog("User allow to access location. Request Location Update"); requestLocationUpdate(); break; case Activity.RESULT_CANCELED: Helper.showLog("User denied to access location."); openGpsEnableSetting(); break; } } else if (requestCode == REQUEST_ENABLE_GPS) { LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); boolean isGpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); if (!isGpsEnabled) { openGpsEnableSetting(); } else { requestLocationUpdate(); } } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_LOCATION_PERMISSION) { int permissionCheck = PermissionChecker.checkCallingOrSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION); if (permissionCheck == PackageManager.PERMISSION_GRANTED) { Helper.showLog("User Allowed Permission Build Google Client"); buildGoogleApiClient(); } else { Helper.showLog("User Denied Permission"); } } } private void openGpsEnableSetting() { Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); startActivityForResult(intent, REQUEST_ENABLE_GPS); } @Override protected void onDestroy() { //Remove location update callback here mFusedLocationClient.removeLocationUpdates(mLocationCallback); super.onDestroy(); } }
Helper Class
public class Helper { public static void showLog(String message) { Log.e("Ketan", "" + message); } public static void showToast(Context context, String message) { Toast.makeText(context, "" + message, Toast.LENGTH_SHORT).show(); } }
Probably, your problem is where you connect the client, I cannot test now, but as google doc shows in the example, you should connect the client in your onStart()
method in the activity.
@Override protected void onStart() { super.onStart(); mGoogleApiClient.connect(); } @Override protected void onStop() { super.onStop(); if (mGoogleApiClient.isConnected()) { mGoogleApiClient.disconnect(); } }
For me, this make getLocation work
1With android APILEVEL
above 23 you need some run time permissions. Location service ACCESS_COARSE_LOCATION
, ACCESS_FINE_LOCATION
are also need permissions.
Checkout this documentation https://developer.android.com/training/permissions/requesting.html
I found the solution.
I was testing my app on a phone with API 22 and it worked fine, however, on API 17 location kept returning null
.
As it turns out, you have to allow your phone to use google location services. You can do it by going to Settings->Location Access->Check the "WLAN & mobile network location"
(it might be called different in another API). Its' description is this:
Let apps use Google's location service to estimate your location faster. Anonymous location data will be collected and sent to Google.
By enabling it, I suddenly began to get much needed fused location data.
Hope this helps!
I don't think that is a coding issue.
Seems that device location provider is having difficulties to pinpoint location on the proposed time, and locationChanged() method is never called.
Check the if the device configuration to location services isn't selected with a harder location mode (like GPS only).
If so, your code can't determine your location by GPS if you are indoor (as I guess you are). Pick the High Accuracy option and your problems will be solved.
This is the exact solution. But I wanted to add some little explanation steps so that anybody gets the exact concepts. Why it is returning null, I agree to follow Amit K answer. But, to guarantee on avoiding location NullPointerException, you start your location related processing inside onLocationChanged() callback.
1) onCreate() of Android Component (Eg, Activity, Fragment or Service. Note: Not IntentService), build and then connect the GoogleApiClient as below.
buildGoogleApiClient(); mGoogleApiClient.connect();
where, buildGoogleApiClient() implementation is,
protected synchronized void buildGoogleApiClient() { Log.i(TAG, "Building GoogleApiClient"); mGoogleApiClient = new GoogleApiClient.Builder(this) .addApi(LocationServices.API) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .build(); }
Later on onDestroy(), you can disconnect GoogleApiClient as,
@Override public void onDestroy() { Log.i(TAG, "Service destroyed!"); mGoogleApiClient.disconnect(); super.onDestroy(); }
The step 1 makes sure you build and connect the GoogleApiClient.
1) GoogleApiClient instance first time gets connected on method onConnected(). Now, your next step should look onConnected() method.
@Override public void onConnected(@Nullable Bundle bundle) { Log.i(TAG, "GoogleApiClient connected!"); buildLocationSettingsRequest(); createLocationRequest(); location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient); Log.i(TAG, " Location: " + location); //may return **null** because, I can't guarantee location has been changed immmediately }
Above, you called a method createLocationRequest() to create location request. The method createLocationRequest() looks like below.
protected void createLocationRequest() { //remove location updates so that it resets LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this); //Import should not be **android.Location.LocationListener** //import should be **import com.google.android.gms.location.LocationListener**; mLocationRequest = new LocationRequest(); mLocationRequest.setInterval(10000); mLocationRequest.setFastestInterval(5000); mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); //restart location updates with the new interval LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this); }
3) Now, on onLocationChange() callback of LocationListener interface, you get new location.
@Override public void onLocationChanged(Location location) { Log.i(TAG, "Location Changed!"); Log.i(TAG, " Location: " + location); //I guarantee of change of location here. }
You get the result like this in Logcat: 03-22 18:34:17.336 817-817/com.LiveEarthquakesAlerts I/LocationTracker: Location: Location[fused 37.421998,-122.084000 acc=20 et=+15m35s840ms alt=0.0]
Note: The location above got is Google Headquarter's location although I am in Arkansas. This happens when you use Emulator. On real device, it shows correct address.
To be able to do these three steps, you should have configured your build.gradle as below:
compile 'com.google.android.gms:play-services-location:10.2.1'
9I was facing the same issue. In my case, the problem was with allowing the permissions for the application. I had denied the FINE LOCATION permission that was asked when the first time app started.
Try uninstalling the app from your device and then redeploying it. It will again ask for the permission. Allow fine location access.
Worked in my case !!
1Try this,
private static int UPDATE_INTERVAL = 10000; // 10 sec private static int FATEST_INTERVAL = 5000; // 5 sec private static int DISPLACEMENT = 10; // 10 meters private void createLocationRequest() { mLocationRequest = new LocationRequest(); mLocationRequest.setInterval(UPDATE_INTERVAL); mLocationRequest.setFastestInterval(FATEST_INTERVAL); mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); mLocationRequest.setSmallestDisplacement(DISPLACEMENT); } @Override public void onConnected(@Nullable Bundle bundle) { mLastLocation = LocationServices.FusedLocationApi .getLastLocation(mGoogleApiClient); if(mLastLocation == null){ LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this); } }
1Check in your device whether you have enabled the location or not.
You can either enable it from Notification Panel or from Settings as:
Settings -> Personal -> Location
I have used only permission that is :
ACCESS_FINE_LOCATION
My working code is:
package com.go.findlocation; import android.content.pm.PackageManager; import android.location.Location; import android.location.LocationManager; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.ActivityCompat; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.widget.TextView; import android.widget.Toast; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.location.LocationListener; import com.google.android.gms.location.LocationRequest; import com.google.android.gms.location.LocationServices; public class MainActivity extends AppCompatActivity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener { private GoogleApiClient mGoogleApiClient = null; //private Location mLocation = null; private LocationManager mLocationManager = null; private LocationRequest mLocationRequest = null; private TextView tv1 = null; private TextView tv2 = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mLocationRequest = new LocationRequest(); mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); mLocationRequest.setInterval(10000); mLocationRequest.setFastestInterval(7000); mLocationRequest.setSmallestDisplacement(1); mGoogleApiClient = new GoogleApiClient.Builder(this) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .addApi(LocationServices.API) .build(); mLocationManager = (LocationManager) getSystemService(LOCATION_SERVICE); tv1 = (TextView) findViewById(R.id.tv1); tv2 = (TextView) findViewById(R.id.tv2); } @Override public void onConnected(@Nullable Bundle bundle) { Log.d("abc", "def"); if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // TODO: Consider calling // ActivityCompat#requestPermissions // here to request the missing permissions, and then overriding // public void onRequestPermissionsResult(int requestCode, String[] permissions, // int[] grantResults) // to handle the case where the user grants the permission. See the documentation // for ActivityCompat#requestPermissions for more details. return; } Log.d("ghi", "jkl"); LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this); Log.d("connected", String.valueOf(mGoogleApiClient.isConnected())); /* if (mLocation != null) { tv1.setText(String.valueOf(mLocation.getLatitude())); tv2.setText(String.valueOf(mLocation.getLongitude())); } else Toast.makeText(this, "mLocation is null", Toast.LENGTH_SHORT).show();*/ } @Override public void onConnectionSuspended(int i) { } @Override public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { } @Override protected void onStart() { mGoogleApiClient.connect(); super.onStart(); } @Override protected void onStop() { if (mGoogleApiClient.isConnected()) mGoogleApiClient.disconnect(); super.onStop(); } @Override public void onLocationChanged(Location location) { if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // TODO: Consider calling // ActivityCompat#requestPermissions // here to request the missing permissions, and then overriding // public void onRequestPermissionsResult(int requestCode, String[] permissions, // int[] grantResults) // to handle the case where the user grants the permission. See the documentation // for ActivityCompat#requestPermissions for more details. return; } Log.d("mno",String.valueOf(mGoogleApiClient.isConnected())); if (location != null) { tv1.setText(String.valueOf(location.getLatitude())); tv2.setText(String.valueOf(location.getLongitude())); Toast.makeText(this, location.getLatitude()+" "+location.getLongitude(), Toast.LENGTH_SHORT).show(); } else Toast.makeText(this, "location is null", Toast.LENGTH_SHORT).show(); } }
1faced similar issue 30min ago, code was running before new simulator. After changing lat lng of simulator it started to work again
1I just made a discovery, maybe it will help some of you. I was getting null from getLastLocation() and it turns out it was because I tried to get the location with only the GPS turned on, but apparently you also have to have Wi-Fi turned on (even if not connected to any network). I am wondering if that's my device fault (Samsung tablet)... I am doing more digging into the topic but as for now nothing found. I would appreciate anyone sharing more knowledge about this issue.
1ncG1vNJzZmirpJawrLvVnqmfpJ%2Bse6S7zGiorp2jqbawutJoaXJvaWuBdIKOsJ%2ByZZmoeqfB0p6bpaeTlsGqu82ap6Jll5rBra3SraOom5GptrC6jKespaQ%3D