Guide To Getting Location in Android(Latitude and Longitude) — Part 1

pic courtesy: https://www.geospatialworld.net/

I have been working as an android developer for two years, and I have seen many people (including me) struggling with getting location data from the phone. Most of the blogs and tutorials that I have gone through are not giving the complete picture. That’s why I decided to write a complete blog on how to get location data on Android.

Note: I expect you to have a minimum knowledge of android development to follow this tutorial.

So enough background let’s begin.

We will make an app with a single button. On clicking the button we will get the longitude and latitude and show it as a toast. We will check if the last known location is already there in the cache if yes then we will show that, and if not we will initiate a location request and display the result.

Google has provided us with a fused location provider which is one of the location API’s in google play services. The API internally handles a lot of things for us like the battery optimization. But since it is a part of Google Play services the device needs to have the google play services installed. It usually comes with the device pre-installed so we won’t have to worry about this in most cases. Unless the phone is rooted and play services are removed or in some cases devices came without google apps(some devices in China comes like this), fusedlocationprovider will work well.

Setting Up Google Play Services

Now as a developer you will have to set up Google play services in your android studio.

  1. Open SDK manager by clicking Tools > SDK Manager or by clicking SDK Manager button
  2. Then go to the SDK Tools tab and check Google Play Services
  3. And click Apply and OK.

4. Now add

implementation ‘com.google.android.gms:play-services-location:15.0.1’

to the application build.gradle file. (you can find the latest version here)

5. Then click Sync Now

Note: Make sure Top level build.gradle has google() added to their repositories.

We can use the following code to check if the play services are available on the user’s phone. Add it to onResume() of your activity. In this example, if play service is not available we will disable the button to get the location

if(GoogleApiAvailability
.getInstance()
.isGooglePlayServicesAvailable(this)
!= ConnectionResult.SUCCESS){
getLocation.setEnabled(false)
}

App Permissions

We will need permissions for getting the location. As the location is considered as a dangerous permission we will also have to get the permission during runtime from the user. First, we need to add the following line in the manifest.

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

Location Service Client

We need a location service client to get the location. To add the location service client add the following piece of code.

private FusedLocationProviderClient mFusedLocationClient;
// ..
@Override
protected void onCreate(Bundle savedInstanceState) {
// ...
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
}

Requesting Last known location

Now we can request for last known location with the fusedlocationproviderclient object. Let’s make a method that requests for location( `getLocation()` ). Before requesting for the last known location, we should request for runtime permission from the user, as the location is a dangerous permission.

private final int LOCATION_PERMISSION = 1001;private Location mLocation;
//...
private void getLocation(){
if(checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[] {Manifest.permission.ACCESS_FINE_LOCATION},LOCATION_PERMISSION);
return;
}
mFusedLocationClient.getLastLocation()
.addOnSuccessListener(this,
new OnSuccessListener<Location>(){
@Override
public void onSuccess(Location location) {
// Got last known location. In some rare situations this can be null.
mLocation = location;
if (location != null) {
Toast.makeText(MainActivity.this,

location.getLatitude()+""+location.getLongitude(),
Toast.LENGTH_SHORT).show();
}
}
});
}

Here LOCATION_PERMISSION is just an integer used to identify the specific permission.

If the permission is not granted already we must listen for the user input(Allow or Deny) by overriding `onRequestPermissionResult` so that we can handle the situation accordingly as shown below:

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode){
case LOCATION_PERMISSION:{
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
getLocation();
} else {
//permission denied! we cant use location services.
}
}
}
}
}

Here if the user has granted the permission we will call `getLocation()` again so we will get a location object that has the longitude and latitude of your last known location. You will only get the location if some other app(like maps or uber) has already requested for location and that location is stored in the cache. If the location is turned off, after using the previous app, the cache will be cleared and you will get null as location. If the location is null there is nothing to worry because we can initiate our own request for our current location.

Location Request

We can customize our location request according to our needs. We have to a create an object of LocationRequest for this. We can configure the request by making use of some of the functions of the LocationRequest class. Let’s make a method for creating the location request.

private void createAndCheckLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(10000);
mLocationRequest.setFastestInterval(5000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(mLocationRequest);
}

setInterval: To specify the interval in which you need to receive location updates. It can also depend on other apps that are requesting the update.

setFastestInterval: The fastest that your app can process the location update.

setPriority: To specify the priority of your location request.

Now we have to check the current settings of the phone to see if the location is turned on. If not we can ask the user to turn the location on.

Note: The following code is in the `createAndCheckLocationRequest()` method itself.

private void createAndCheckLocationRequest() {
....
SettingsClient client = LocationServices.getSettingsClient(this);
Task<LocationSettingsResponse> task = client.checkLocationSettings(builder.build());
task.addOnSuccessListener(this, new OnSuccessListener<LocationSettingsResponse>() {
@Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
requestLocationUpdate();
}
});
task.addOnFailureListener(this, new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
if (e instanceof ResolvableApiException) {
// Location settings are not satisfied, but this can be fixed
// by showing the user a dialog.
try {
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
ResolvableApiException resolvable = (ResolvableApiException) e;
resolvable.startResolutionForResult(MainActivity.this,
REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException sendEx) {
// Ignore the error.
}
}
}
});
}

Here in the LocationSettingsResponse Task, we are checking if the required settings are satisfied, which means we are checking if the location is turned on. Then we are attaching a success listener and failed listener to the task. The success listener will get invoked if the settings requirement is satisfied and the failed listener will get invoked if it is not. In the failed listener we are checking if the error can be resolved

if (e instanceof ResolvableApiException){ ... }

In our case, it can be resolved by turning on the location. Hence we will be asking the user to turn on the location with startResolutionForResult. We have to pass another integer to this function which is REQUEST_CHECK_SETTINGS.

Again we have to wait for the user to give an input

Requesting user to turn on location

To get the user’s input to this we have to override `onActivityResult` like this:

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == REQUEST_CHECK_SETTINGS){
if(resultCode == Activity.RESULT_OK){
requestLocationUpdate();
}else{
Toast.makeText(this,"Location request not satisfied",Toast.LENGTH_SHORT).show();
}
}
}
}

Here we will check for the request code to make sure we are checking the result of the same request we made and also the result code to know the user input. It will be Activity.RESULT_OK if the user clicked OK. Here we can Request the location update.

private void requestLocationUpdate() {
if(checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_PERMISSION);
}
mFusedLocationClient.requestLocationUpdates(mLocationRequest,
mLocationCallback,
null);
}

RequestLocationUpdate will take some time to complete, roughly 1–2 seconds the first time. We will be passing in a callback(mLocationCallback) to requestLocationUpdates so that the callback will get invoked when the location is available. It can be declared as a global variable:

private LocationCallback mLocationCallback = mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult == null) {
return;
}
for (Location location : locationResult.getLocations()) {
// Update UI with location data
mLocation = location;
Toast.makeText(MainActivity.this, "Lat :" + location.getLatitude() + " Long :" + location.getLongitude(), Toast.LENGTH_SHORT).show();
}
mFusedLocationClient.removeLocationUpdates(mLocationCallback);
}
};

We can remove the location updates if you don’t want to get the periodic update anytime with removeLocationUpdates().

Now i will call the getLocation() on clicking a button in onCreate() as shown below:

private Button getLocation;….@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getLocation = findViewById(R.id.get_location);
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
getLocation.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
getLocation();
}
});
}

That’s all to it folks. The GitHub link of the whole project is here. I will make a part 2 of this tutorial which shows how to get location address from google.

Software Engineer