Using Fused Location API To Fetch Current Location
After booking an Uber cab, have you noticed the movement of cabs on the roads while coming to your address? There are various applications that use some kind of location services. Using GPS to update the location is a very cool feature. That moving icon of a car(in case of Uber) looks very cool and being an Android developer, we all have thought of using these type of features in our mobile application but ended up with some kind of error while integrating this feature.
So, don’t worry, in this blog we will learn how to use Fused Location API to get the accurate location of your Android device by making use of your phone’s own GPS. We will show the current location of the mobile using the GPS and whenever the location of the phone will be updated then the updated location will be shown on the app. So, let’s get started.
Before moving forward
Before moving forward to the coding part, we need to understand the location permissions.
Location Permissions
If you want to get the current location of your user, then you have to add the location permission to your application. Android provides the following location permission:
-
ACCESS_COARSE_LOCATION
: By adding this in your application, allows you to use WIFI or mobile cell data(or both) to determine the device’s location. The approximation by using this permission is close to the city level. -
ACCESS_FINE_LOCATION
: This uses your GPS as well as WIFI and mobile data to get the most precise location as possible. By using this, you will get a precise location of your user. -
ACCESS_BACKGROUND_LOCATION
: This permission was introduced in Android 10. So, for Android 10 or higher, if you want to access the user's location in the background, then along with any of the above two permissions, you need to add the ACCESS_BACKGROUND_LOCATION permission also.
Also, one thing to be noted here is that we are using dangerous permission, so we need to explicitly ask the user to grant permissions. Learn more about permissions from our blog.
So, we are done with the pre-requisite and now we will learn how to get the current location with the help of an example.
Find the whole project on MindOrksOpenSource page.
Example
In this example, we will use
Fused Location API
to get the changed location or you may say, get the current location of a user. We will be using
LocationRequest
that are used to request quality of service for location updates from the
FusedLocationProviderApi
.
Apart from getting the updated location, the
LocationRequest
includes various methods for retrieving locations like a pro. Some of the methods are:
- setInterval(long millis): This is used to set the desired interval after which you want to check for a location update. It is in milliseconds.
-
setFastestInterval(long millis):
This is used to set the fastest interval for a location update. This might be faster than your
setInterval(long)
in many cases because if other applications on the device are triggering location updates at an interval lesser than your interval then it will use that update. - setSmallestDisplacement(float smallestDisplacementMeters): This will set the minimum displacement between location updates i.e. the smallest displacement required for a location update. It is in meters and the default value of this is 0.
-
setPriority(int priority):
This is used to set the priority of location received. It can be
PRIORITY_BALANCED_POWER_ACCURACY
(for accuracy up to block level) or it can bePRIORITY_HIGH_ACCURACY
(to get the most accurate result) or it can bePRIORITY_LOW_POWER
(to get the accuracy up to city level) or it can bePRIORITY_NO_POWER
(to get the most accurate information without providing some additional power).
Get the full list of available methods from here .
Now, follow the below steps to get your current location using Fused Location Provider:
Create a Project
- Start a new Android Studio Project
- Select Empty Activity and Next
- Name: Fused-Location-API-Example
- Package name: com.mindorks.example.fusedlocation
- Language: Kotlin
- Finish
- Your starting project is ready now
Add dependencies
In order to use the Fused Location API, you need to add the dependency of location. So, in your app-level
build.gradle
file, add the below dependency:
dependencies {
...
implementation 'com.google.android.gms:play-services-location:17.0.0'
}
Sync the project.
Adding Permissions
To use location services, you need to add permission for location in the
AndroidManifest.xml
file. You can either use
ACCESS_COARSE_LOCATION
or
ACCESS_FINE_LOCATION
, based on your use:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Making layout file
In this project, we will be having two TextViews, one for latitude and one for longitude. The current location of the user will be displayed in these TextViews. So, the code for the
activity_main.xml
file will be:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:orientation="vertical">
<TextView
android:id="@+id/latTextView"
android:layout_width="match_parent"
android:layout_height="60sp"
android:text="@string/default_lat"
android:gravity="center"
android:layout_marginBottom="8dp"
android:textColor="@color/colorBlack"/>
<TextView
android:id="@+id/lngTextView"
android:layout_width="match_parent"
android:layout_height="60sp"
android:text="@string/default_lng"
android:gravity="center"
android:layout_marginBottom="8dp"
android:textColor="@color/colorBlack"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Now, we are done with all the dependencies and layout part.
Taking permission from the user
Since we are using a dangerous permission of location, so we need to explicitly ask for permission. Also, before getting the current location of the user, the following cases may arise:
We need to write the function for all these permission checks. So, make a package in the root directory and create an object class in that package.
- Package name: com.mindorks.example.fusedlocation.utils
- Object class name: PermissionUtils
Add the below code in the
PermissionUtils.kt
file:
object PermissionUtils {
/**
* Function to request permission from the user
*/
fun requestAccessFineLocationPermission(activity: AppCompatActivity, requestId: Int) {
ActivityCompat.requestPermissions(
activity,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
requestId
)
}
/**
* Function to check if the location permissions are granted or not
*/
fun isAccessFineLocationGranted(context: Context): Boolean {
return ContextCompat
.checkSelfPermission(
context,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
}
/**
* Function to check if location of the device is enabled or not
*/
fun isLocationEnabled(context: Context): Boolean {
val locationManager: LocationManager =
context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
|| locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
}
/**
* Function to show the "enable GPS" Dialog box
*/
fun showGPSNotEnabledDialog(context: Context) {
AlertDialog.Builder(context)
.setTitle(context.getString(R.string.enable_gps))
.setMessage(context.getString(R.string.required_for_this_app))
.setCancelable(false)
.setPositiveButton(context.getString(R.string.enable_now)) { _, _ ->
context.startActivity(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS))
}
.show()
}
}
Writing code for
MainActivity.kt
file
Now, in the MainActivity.kt file, override the
onStart()
method and check if permissions are granted or not using the
PermissionUtils
class and if the permission is granted and the GPS is enabled in the device, then call the
setUpLocationListener()
function that is responsible for getting the current location. The following is the code of
onStart()
:
override fun onStart() {
super.onStart()
when {
PermissionUtils.isAccessFineLocationGranted(this) -> {
when {
PermissionUtils.isLocationEnabled(this) -> {
setUpLocationListener()
}
else -> {
PermissionUtils.showGPSNotEnabledDialog(this)
}
}
}
else -> {
PermissionUtils.requestAccessFineLocationPermission(
this,
LOCATION_PERMISSION_REQUEST_CODE
)
}
}
}
now, make a function named
setUpLocationListener()
. In the function, create an instance of the Fused Location Provider client.
private fun setUpLocationListener() {
val fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this)
}
Now, we need to define the type of location request that we want i.e. we can set the desired level of accuracy of location, the desired interval of location update, desired priority, etc. All these settings can be done by using the
LocationRequest
data object. So, we can add the below code:
// for getting the current location update after every 2 seconds with high accuracy
val locationRequest = LocationRequest().setInterval(2000).setFastestInterval(2000)
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
Now, all we need to do is call the
requestLocationUpdates()
method and pass the
LocationRequest
and a
LocationCallback.
After that, the onLocationResult will be invoked and it contains a list of locations. You can get the latitude and longitude from this location variable and use it as per your choice. Here, we are updating our TextView with this latitude and longitude. So, the final code of
setUpLocationListener()
will be:
private fun setUpLocationListener() {
val fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this)
// for getting the current location update after every 2 seconds with high accuracy
val locationRequest = LocationRequest().setInterval(2000).setFastestInterval(2000)
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
fusedLocationProviderClient.requestLocationUpdates(
locationRequest,
object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
super.onLocationResult(locationResult)
for (location in locationResult.locations) {
latTextView.text = location.latitude.toString()
lngTextView.text = location.longitude.toString()
}
// Few more things we can do here:
// For example: Update the location of user on server
}
},
Looper.myLooper()
)
}
Finally, add the callback for the result from requesting permissions:
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when (requestCode) {
LOCATION_PERMISSION_REQUEST_CODE -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
when {
PermissionUtils.isLocationEnabled(this) -> {
setUpLocationListener()
}
else -> {
PermissionUtils.showGPSNotEnabledDialog(this)
}
}
} else {
Toast.makeText(
this,
getString(R.string.location_permission_not_granted),
Toast.LENGTH_LONG
).show()
}
}
}
}
That's it.
Run the application
Run the application on your device and try to verify all the cases of permission and also try to change the location of your device to find if the location is updating on the TextView or not.
Find the whole project on MindOrksOpenSource page.
Summary
In this blog, we learned how to display the changed location of the user in your app. We have used the Fused Location API for the same purpose.
You can use this concept while making some ride-sharing application. Learn how to build a ride-sharing Android app like Uber, Lyft with MindOrks open-Source Project.
Keep Learning :)
Team MindOrks!