Why is FusedLocationApi.getLastLocation null

56,904

Solution 1

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.

Solution 2

I 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..

Solution 3

If 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.

Solution 4

I 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();
    }
}

May Help

Solution 5

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

Share:
56,904

Related videos on Youtube

Can Poyrazoğlu
Author by

Can Poyrazoğlu

Has most experience in iOS programming and UI design. Loves astrophotography, board sports, feeding street animals, authoring his humble blog, and flying drones.

Updated on July 10, 2020

Comments

  • Can Poyrazoğlu
    Can Poyrazoğlu almost 4 years

    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.

    • CommonsWare
      CommonsWare about 9 years
      There are no ACCESS_GPS or ACCESS_LOCATION permissions in Android. Beyond that, it is very difficult to help you without code.
    • Can Poyrazoğlu
      Can Poyrazoğlu about 9 years
      @CommonsWare I don't know how I ended up that way, anyway, it shouldn't affect the behavior.
    • Amit K. Saha
      Amit K. Saha about 9 years
      are you testing on real device? besides documentation says, If client is not connected null will be returned. make sure your client is connected at all.
    • Borja Alvarez
      Borja Alvarez about 9 years
      Could you paste the code where you initialize api client and where you get null?
    • Napolean
      Napolean about 9 years
      for avoiding null location try using both the providers GPS_PROVIDER and NETWORK_PROVIDER and hence add netwrok specific permissions
    • Can Poyrazoğlu
      Can Poyrazoğlu about 9 years
      @AmitK.Saha yes, it's a real device, see my updated question.
    • Can Poyrazoğlu
      Can Poyrazoğlu about 9 years
      @BorjaAlvarez updated the question.
    • Ravi Bhandari
      Ravi Bhandari about 9 years
      @Can Poyrazoğlu hade you check my answer.YOu can also check it by seting LocationRequest.PRIORITY_HIGH_ACCURACY, because there may be no such app that geting location update in your device.
    • lagos
      lagos over 8 years
      Any solution on this?
    • Haikal Nashuha
      Haikal Nashuha over 7 years
      @lagos yes, just follow the first answer.
    • Subho
      Subho about 7 years
      I request all of you please take a look at this answer stackoverflow.com/a/35833552/3278589
    • Saik Caskey
      Saik Caskey almost 7 years
      that answer is exactly the same crap that is all over this post. The question is not concerning location callbacks, the question is concerning FusedLocationProvider returning null for getLastLocation. I for one am seeing it say null, then report correctly, then report null again seconds later, on only some devices.
  • DJ_Polly
    DJ_Polly almost 9 years
    Note that you need to implement GoogleApiClient.ConnectionCallbacks and com.google.android.gms.location.LocationListener
  • Mrigank
    Mrigank over 8 years
    You should disconnect the google api client before calling on the super method in OnStop() of your Activity class.
  • Alexey Strakh
    Alexey Strakh almost 8 years
    so what is the major difference with the author's code? Sequence of commands?
  • Can Poyrazoğlu
    Can Poyrazoğlu over 7 years
    don't you think I've tried all the possible combinations of location settings?
  • Haikal Nashuha
    Haikal Nashuha over 7 years
    @AlexeyStrakh Yes. When the app starts the googleApiClient's lastLocation object was null. Consequently, calling last location on null object will return null, so the algorithm should be improved by first updating the location, then when googleApiClient acquired current location, you proceed by asking it. Be careful tho as if the location doesn't change, the onLocationChanged will not be triggered.
  • Ersen Osman
    Ersen Osman about 7 years
    This is correct, I had a similar issue a while back stackoverflow.com/q/35830987/4243687 The lastKnownLoction is simply a cached location. In fact, when other apps request a location, this location is then cached
  • Saik Caskey
    Saik Caskey almost 7 years
    You don't even use fusedLocationProviderApi ... the question is "Why is FusedLocationApi.getLastLocation null" not "how do I location updates without FusedLocationApil"
  • Saik Caskey
    Saik Caskey almost 7 years
    That doesn't come close to explaining why it is null
  • Saik Caskey
    Saik Caskey almost 7 years
    everyone knows where the boilerplate code can be found.. the question was about why the provider would return null for last location
  • Uddhav P. Gautam
    Uddhav P. Gautam almost 7 years
    1) If it GoogleApiClient doesn't find the Location object then it returns the null. It is a very obvious thing.
  • Saik Caskey
    Saik Caskey almost 7 years
    That is not a helpful response. Obviously OP wouldn't be asking if it was an obvious issue
  • Uddhav P. Gautam
    Uddhav P. Gautam almost 7 years
    @SaikCaskey, mind your language man. This is absolutely not the boilerplate code that I found on the internet. I have developed a complex project and wrote the research paper. I put the snippet here. You might want to see my app, which uses FusedLocationProvider. play.google.com/store/apps/…. Further, there is onLocationChanged() callback, which can absolutely guarantee that you got the location. You can customize your location requests accordingly.
  • Saik Caskey
    Saik Caskey almost 7 years
    Watch my language? :S You still aren't answering the question... added to that, how is this anything but boilerplate code? Just because you use it in your app or used it for a research paper doesn't mean it's yours, or that it's not very easy to find (ahem: developer.android.com/training/location/… .. your code is almost identical). You cannot absolutely guarantee that there will be a last location unless everything is working, the case where this is not the case is the case explored in this question
  • Uddhav P. Gautam
    Uddhav P. Gautam almost 7 years
    @SaikCaskey, I guarantee there is last location inside onLocationChange() callback. It is absolutely zero change that onLocationChange() be called in Null location. And If onLocationChang() is giving new location in every my location request (which I can ask in every 2 seconds), I can guarantee I am getting my new location.
  • Uddhav P. Gautam
    Uddhav P. Gautam almost 7 years
    @SaikCaskey, why the location is returning null, it depends on system. FocusedLocation Provider based on your current condition intelligently switches to various location providing systems (like GPS, Wifi, Internet .. etc). It is kind of very hard to exactly explain this. But I explained on how we can avoid NullPointerException.
  • Saik Caskey
    Saik Caskey almost 7 years
    "It is absolutely zero change that onLocationChange() be called in Null location" - that is simply not relevant to the question actually (getLastLocation). The question "Why is FusedLocationApi.getLastLocation null" is not answered by "here's my code" and "here's how to avoid a null pointer". "it depends on system" is a much better answer, although it's exactly as useful to people experiencing the problem as "here's my code"
  • Uddhav P. Gautam
    Uddhav P. Gautam almost 7 years
    @SaikCaskey, I said it clearly in my answer. I never said my answer is his exact answer. But it solves the issues in the practical world. I was stuck during that time when I wanted to solve my issues. Therefore, I thought providing exactly working code helps other developers. It is my trying man, you are welcome to like it.
  • Daniel O
    Daniel O over 4 years
    I had same issue as OP but while using the emulator, after I manually set the device's location. Opening Maps in the emulator fixed this for me.
  • kaiya
    kaiya almost 2 years
    Uninstalling is not necessary. Permissions can be modified during execution of applications.
  • kaiya
    kaiya almost 2 years
    This doesn't answer the question of "Why is ...?"
  • kaiya
    kaiya almost 2 years
    The answer contains only a guess and no explanation even though previous posts have already pointed out the problem.