Android: getLastLocation() returning null

Recently I was learning Android and was developing an android app which uses Android LocationServices. I followed the google documentation and every time it was returning null when I was trying to get the location and show it on map and my map failed to initialize. I had to mess around to find the reason and got it working and will share it here to help other developers.

Note: I am a beginner in android so this may not be the best instruction and also point me if I am wrong or you find something better.

Back to the point after declimer..:-). 

getLastLocation() returns null if you are initializing map and querying for last location and try to show it on map before the API has returned user's location or if location is not known.

The reason for location not known can be because user has turned off location services. For this you can alert user to switch on the GPS.

Talking about the first reason, correct procedure to not get null when initializing map to user location is to initialize the map on onConnected() callback instead of onCreate() in an activity or fragment. Full procedure is as follows.

So, first setup google play services, you can follow this link if need help.

Then specify app permission in manifest file as follows.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.google.android.gms.location.sample.basiclocationsample" >
  
  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
</manifest>

if you want more accurate location then you can ask for ACCESS_FINE_LOCATION. 

Next step is to connect to google play Services. call it from activities onCreate() method as:

mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();

Then connect to the client in onStart() method:

@Override
    protected void onStart() {
        super.onStart();
        // Connect the client.
        mGoogleApiClient.connect();
    }

After then override the onConnected() method by querying user's location and initializing map with the location. The code for it is as follows:

@Override
    public void onConnected(Bundle bundle) {
        Location location = LocationServices.FusedLocationApi.getLastLocation(
                mGoogleApiClient);
        if (location != null) {
            MapFragment mapFragment = (MapFragment) getFragmentManager()
                    .findFragmentById(R.id.map);
            mapFragment.getMapAsync(this);
        }
        else {
            new AlertDialog.Builder(MainActivity.this)
                    .setTitle("Please activate location")
                    .setMessage("Click ok to goto settings else exit.")
                    .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                            Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                            startActivity(intent);
                        }
                    })
                    .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                            System.exit(0);
                        }
                    })
                    .show();
        }
    }

Here we are first getting user's location by

 Location location = LocationServices.FusedLocationApi.getLastLocation(
                mGoogleApiClient);

then if it isn't null, we are saving the user location in a global variable and then initializing the MapFragment and calling the getMapAsync() method. Else code prompts the user to activate location services if location is null.

This calls the onMapReady() method, which you can override to initialize map at user's current location and position marker there as follows:

 @Override
    public void onMapReady(GoogleMap map) {
        LatLng userLocation = new LatLng(currentLocation.getLatitude(),currentLocation.getLongitude());
        map.setMyLocationEnabled(true);
        map.moveCamera(CameraUpdateFactory.newLatLngZoom(userLocation, 13));
        Marker marker = map.addMarker(new MarkerOptions()
                .title("Hii there!!")
                .position(userLocation)
                .draggable(true)
                .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE)));
        marker.showInfoWindow();
    }

To learn  about adding and customising the marker follow here.

Comment if you have any bug or error, will try to learn together!!!