Why is FusedLocationApi.getLastLocation null

2019-01-08 21:52发布

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.

13条回答
太酷不给撩
2楼-- · 2019-01-08 21:58

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

查看更多
爷的心禁止访问
3楼-- · 2019-01-08 22:00

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.

查看更多
\"骚年 ilove
4楼-- · 2019-01-08 22:02

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

查看更多
时光不老,我们不散
5楼-- · 2019-01-08 22:04

With 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
6楼-- · 2019-01-08 22:11

Try 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);
        }
    }
查看更多
该账号已被封号
7楼-- · 2019-01-08 22:12

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'
查看更多
登录 后发表回答