LocationClient getLastLocation() return null

AndroidGpsLocation

Android Problem Overview


Like the questions someone encountered before I tested one the nexus s(4.0.4 with google play service available) and avd (4.2.2 with google api), in both case locationclient's getLastLocation() always return null.

public class MainActivity extends Activity implements LocationListener,
		GooglePlayServicesClient.ConnectionCallbacks,
		GooglePlayServicesClient.OnConnectionFailedListener {

	private LocationClient mLocationClient;
	private LocationRequest mLocationRequest;
	boolean mUpdatesRequested = false;
	boolean mConnected = false;
	SharedPreferences mPrefs;
	SharedPreferences.Editor mEditor;
	private TextView mText;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		mText = (TextView) findViewById(R.id.text);
		mLocationRequest = LocationRequest.create();
		mLocationRequest
				.setInterval(LocationUtils.UPDATE_INTERVAL_IN_MILLISECONDS);
	mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
		mLocationRequest
.setFastestInterval(LocationUtils.FAST_INTERVAL_CEILING_IN_MILLISECONDS);
		mUpdatesRequested = false;
		mPrefs = getSharedPreferences(LocationUtils.SHARED_PREFERENCES,
				Context.MODE_PRIVATE);
		mEditor = mPrefs.edit();
		mLocationClient = new LocationClient(this, this, this);
	}
	@Override
	public void onStart() {
		super.onStart();
		/*
		 * Connect the client. Don't re-start any requests here; instead, wait
		 * for onResume()
		 */
		mLocationClient.connect();
	}

	@Override
	protected void onResume() {
		super.onResume();
		// If the app already has a setting for getting location updates, get it
		if (mPrefs.contains(LocationUtils.KEY_UPDATES_REQUESTED)) {
			mUpdatesRequested = mPrefs.getBoolean(
					LocationUtils.KEY_UPDATES_REQUESTED, false);
			// Otherwise, turn off location updates until requested
		} else {
			mEditor.putBoolean(LocationUtils.KEY_UPDATES_REQUESTED, false);
			mEditor.commit();
		}
	}
	@Override
	public void onStop() {
		// If the client is connected
		if (mLocationClient.isConnected()) {
			stopPeriodicUpdates();
		}
		// After disconnect() is called, the client is considered "dead".
		mLocationClient.disconnect();
		super.onStop();
	}

	@Override
	public void onPause() {
		// Save the current setting for updates
		mEditor.putBoolean(LocationUtils.KEY_UPDATES_REQUESTED,
				mUpdatesRequested);
		mEditor.commit();
		super.onPause();
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}
	public void getLocation(View v) {
		// If Google Play Services is available
		if (isGooglePlayServicesAvailable()) {
			if (!mConnected)
				mText.setText("location client is not connected to service yet");
			else {
				// Get the current location
				Location currentLocation = mLocationClient.getLastLocation();
				// Display the current location in the UI
				mText.setText(LocationUtils.getLocationString(currentLocation));
			}
		}
	}

	private boolean isGooglePlayServicesAvailable() {

		// Check that Google Play services is available
		int resultCode = GooglePlayServicesUtil
				.isGooglePlayServicesAvailable(this);

		// If Google Play services is available
		if (ConnectionResult.SUCCESS == resultCode) {
			// In debug mode, log the status
			Log.d(LocationUtils.APPTAG, "google play service is available");

			// Continue
			return true;
			// Google Play services was not available for some reason
		} else {
			// Display an error dialog
			Dialog dialog = GooglePlayServicesUtil.getErrorDialog(resultCode,
					this, 0);
			if (dialog != null) {
				Log.e(LocationUtils.APPTAG,
						"google play service is unavailable");
			}
			return false;
		}
	}

	private void stopPeriodicUpdates() {
		mLocationClient.removeLocationUpdates(this);
		// mConnectionState.setText(R.string.location_updates_stopped);
	}

	@Override
	public void onConnectionFailed(ConnectionResult arg0) {
		mConnected = false;
		Log.d(LocationUtils.APPTAG, "connection failed");
	}

	@Override
	public void onConnected(Bundle arg0) {
		mConnected = true;
		Log.d(LocationUtils.APPTAG,
				"location client connected to the location server");
		LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
		lm.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, 0, 0,
				new android.location.LocationListener() {
					@Override
					public void onStatusChanged(String provider, int status,
							Bundle extras) {}

					@Override
					public void onProviderEnabled(String provider) {}

					@Override
					public void onProviderDisabled(String provider) {}

					@Override
					public void onLocationChanged(final Location location) {
					}
				});
		Log.d(LocationUtils.APPTAG, "done trying to get location");
	}

	@Override
	public void onDisconnected() {
		// TODO Auto-generated method stub
		mConnected = false;
		Log.d(LocationUtils.APPTAG,
				"location client disconnected from the location server");
	}

	@Override
	public void onLocationChanged(Location arg0) {}

}

most of them came from examples given by google. In the code above hava tried the method like that:

LocationRequest request = LocationRequest.create();
request.setNumUpdates(1);
mLocationClient.requestLocationUpdates(request, this);

and

LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

		lm.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, 0, 0,
				new android.location.LocationListener() {
					@Override
					public void onStatusChanged(String provider, int status,Bundle extras) {}

					@Override
					public void onProviderEnabled(String provider) {}

					@Override
					public void onProviderDisabled(String provider) {}

					@Override
					public void onLocationChanged(final Location location) {}
				});

In onConnected() before calling getLastLocation(), but still get no luck. Where's the mistake, Thanks in advance.

Android Solutions


Solution 1 - Android

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.

Solution 2 - Android

I had the same problem when following the instructions from the tutorial. On phone it worked and on the (Genymotion) emulator it didn't.

Solution

In your AndroidManifest.xml, change this:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

to this:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

...and you get the location immediately. No need to change your code (to listen to location updates).

Solution 3 - Android

The issue can also be caused by your device does not have "Wi-Fi & mobile network location" enabled.

LocationClient (the fused location provider) uses both GPS and WiFi. GPS takes a while to find your location while wifi is much faster. However, if any one of these 2 services is connected, the call back method onConnected will be called. And if you are trying to call LocationClient.getLastLocation() in the onConnected method immediately, it is mostly likely that you will get null value if your wifi location service is disabled. It is just because GPS is simply not fast enough.

To solve the problem for yourself locally, enable "Wi-Fi & mobile network location". You can do it by going to "Settings > Personal > Location access > Wi-Fi & mobile network location".

However, if you want to solve the issue for the users of your app, you'd better check whether getLastLocation() returns null. If it does, prompt your user to enable the service just like google map does.

Hopefully, that helps.

Solution 4 - Android

I was facing a similar issue.

Call mLocationClient.getLastLocation() in onConnected or after the Connection to Google Play Services has been established. If you're calling this method before the Location Client is connected, the location returned would be null.

You could check if the location client is connected by mLocationClient.isConnected().

Hope this helps.

Solution 5 - Android

I faced similar issues on my tests with Samsung phones (highly customized android, and no developer support).

LocationManager and LocationClient dont get the GPS from the providers. They need to be kickstarted everytime you need the location from them. Do this before your LocationManager.getLastKnownLocation OR LocationClient.getLastLocation calls. These API's will return.

YOUR_APPLICATION_CONTEXT.getLocationManager().requestLocationUpdates(
    LocationManager.NETWORK_PROVIDER, 0, 0, new LocationListener() {
        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
        }
        @Override
        public void onProviderEnabled(String provider) {
        }
        @Override
        public void onProviderDisabled(String provider) {
        }
        @Override
        public void onLocationChanged(final Location location) {
        }
    });

Solution 6 - Android

This is the exactly working solution, probaly in slight different circumstances. But I wanted to add some little explanation steps so that anybody gets the exact concepts:

  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,I get the changed 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]

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'

Solution 7 - Android

You must check if user has enabled location via Wi-Fi/GSM or GPS. If there isn't any available location provider, you get null.

This code displays the screen with location settings:

startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));

Solution 8 - Android

On SDK versions 23

You will also need to explicitly request the location permission during runtime, as per https://developer.android.com/training/permissions/requesting.html as well as having it in the manifest file.

No explicit error will occur if you do not have the permissions during runtime, the location provider will just return null.

It would help if Google documented this, and also throw an exception rather than just returning null. Returning null is about the least helpful thing to do in this situation.

Solution 9 - Android

I was also facing the same issue on my app, and the only missing thing was that the app only requested for ACCESS_COARSE_LOCATION and not ACCESS_FINE_LOCATION. I added the later permission and everything worked OK.

Solution 10 - Android

You just need an update request for the location. If with 26 Android SDK permitions is all ok:

private void setLocation(Context context) {
    GoogleApiClient googleApiClient = new GoogleApiClient.Builder(context)
            .addApi(LocationServices.API).build();
    googleApiClient.connect();

     locationRequest = LocationRequest.create();
    locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    locationRequest.setInterval(2000);
    locationRequest.setFastestInterval(2000);

    LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(locationRequest);
    builder.setAlwaysShow(true);
    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();
            switch (status.getStatusCode()) {
                case LocationSettingsStatusCodes.SUCCESS:
                    showMessage(" All location settings are satisfied.");
                    mGoogleApiClient = new GoogleApiClient.Builder(MainActivity.this)
                            .addApi(LocationServices.API)
                            .addConnectionCallbacks(connectionCallbacks)
                            .addOnConnectionFailedListener(connectionFailedListener)
                            .build();
                            mGoogleApiClient.connect();
                    break;
                case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
                    l.a(" Location settings are not satisfied. Show the user a dialog to upgrade location settings ");

                    try {
                        // Show the dialog by calling startResolutionForResult(), and check the result
                        // in onActivityResult().
                        status.startResolutionForResult(MainActivity.this, REQUEST_CHECK_SETTINGS);
                    } catch (IntentSender.SendIntentException e) {
                        showMessage("PendingIntent unable to execute request.");
                    }
                    break;
                case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
                    showMessage("Location settings are inadequate, and cannot be fixed here. Dialog not created.");
                    break;
            }
        }
    });
}

and in onConnected callback method:

 @Override
    public void onConnected(@Nullable Bundle bundle) {
        l.a(3232);
        if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) !=
                PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                   return;
        }

            mLastLocation = LocationServices.FusedLocationApi.getLastLocation(
                    mGoogleApiClient);
       if(null==mLastLocation){//  !!!!!!!!!!!! here it can happen !!!!!!!

                    LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, locationRequest, new LocationListener() {
                        @Override
                        public void onLocationChanged(Location location) {
                            mLastLocation = location;
                            locationWasFound = true;
                            sevumPora.setLocation(mLastLocation);
                            mGoogleApiClient.disconnect();
                        }
                    });
                return;
            }
        locationWasFound = true;
        sevumPora.setLocation(mLastLocation);
        mGoogleApiClient.disconnect();
    }

Solution 11 - Android

I run and its working perfect in Nexus 7 device. You guys by mistake written old version LocationListener which is not used with new API.

You have to set with new LocationListener.

You need to import this class and then try.

import com.google.android.gms.location.LocationListener;

And it override the only one method as per new API

@Override
public void onLocationChanged(final Location newLocation) 
{}

Please try this way and let me know if you still facing any issue.

Thanks.

Solution 12 - Android

Google play service geolocation can't work without internet connection, indifferently for GPS. So, please check app with mobile data switched on.

Solution 13 - Android

The easiest fix, albeit slows it down a little, is to use a helper function. My problem was that it would connect, but before there was a location found, I would try to access it and hit a null pointer.

public Location getLocation(LocationClient locationClient){

    if(locationClient.getLastLocation() == null){
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return getLocation(locationClient);
    }else{
        return locationClient.getLastLocation();
    }
}

Just use this in onConnected and set whatever you wanted the location to be using this function, passing your location client.

@Override
public void onConnected(Bundle dataBundle) {

    Location temp = getLocation(mLocationClient);
    mLocation = temp;
}

Also if you don't want to get the location from onConnected for whatever reason, you can use the same helper function anywhere as long as you pass your locationClient.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionoscarthecatView Question on Stackoverflow
Solution 1 - AndroidDavidView Answer on Stackoverflow
Solution 2 - AndroidSaranView Answer on Stackoverflow
Solution 3 - AndroidTim HongView Answer on Stackoverflow
Solution 4 - AndroidRahul SainaniView Answer on Stackoverflow
Solution 5 - AndroidSiddharthView Answer on Stackoverflow
Solution 6 - AndroidUddhav P. GautamView Answer on Stackoverflow
Solution 7 - AndroidPitelView Answer on Stackoverflow
Solution 8 - AndroidMarkView Answer on Stackoverflow
Solution 9 - AndroidgfhuertacView Answer on Stackoverflow
Solution 10 - AndroidCodeToLifeView Answer on Stackoverflow
Solution 11 - AndroidPrashantAdesaraView Answer on Stackoverflow
Solution 12 - Androiduser1575120View Answer on Stackoverflow
Solution 13 - Androidnvcballer15View Answer on Stackoverflow