Fused Location Provider in Kotlin

1. Add the dependency

Go to your build.gradle (Module: app) file and add this.

implementation 'com.google.android.gms:play-services-location:19.0.1'
viewBinding {
enabled = true
}

2. Add the permissions

Go to your AndroidManifest.xml file and add these 2 permissions

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

3. Setting up the layout

Go to your activity_main.xml file. We will be adding two text views for latitude and longitude. Plus a button to refresh our location.

<?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">

<TextView
android:id="@+id/latitudeText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/latitude"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:textSize="20sp"
android:layout_marginBottom="16dp"/>

<TextView
android:id="@+id/longitudeText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/longitude"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/latitudeText"
android:layout_marginTop="16dp"
android:textSize="20sp"/>

<Button
android:id="@+id/refreshButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/refresh"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginBottom="16dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>

4. MainActivity.kt

There is a lot going on in the main activity file so I will briefly explain what is going on. First, the app checks to see if the GPS is enabled in the device’s settings. If it is not, it will call the showAlertMessage function. This function will display an alert dialog box that asks the user if they want to enable the device’s GPS. The checkForPermission function is then called which checks if the app granted the location permission. If it did not, it gives the user an option to allow it or deny it. The onRequestPermssionsResult function checks to see if you allowed the app the location permission and then calls the startLocationUpdates function. The startLocationUpdate function starts requesting location updates every 5 seconds. You can change how quickly you want the updates to be by changing the interval and fastestInterval variables. There are also different types of priorities for the location request. If you want the location requests to be accurate, use PRIORITY_HIGH_ACCURACY. If you want to save the device’s battery and the location to be not so accurate, use PRIORITY_LOW_POWER. There’s also PRIORITY_NO_POWER and PRIORITY_BALANCED_POWER_ACCURACY.

class MainActivity : AppCompatActivity() {

private lateinit var binding: ActivityMainBinding
private var fusedLocationProviderClient: FusedLocationProviderClient? = null
private var longitude: Double = 0.0
private var latitude: Double = 0.0
private val interval: Long = 10000 // 10seconds
private val fastestInterval: Long = 5000 // 5 seconds
private lateinit var mLastLocation: Location
private lateinit var mLocationRequest: LocationRequest
private val requestPermissionCode = 999

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)

fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this)
mLocationRequest = LocationRequest.create()
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
showAlertMessage()
}
checkForPermission(this)
startLocationUpdates()
}

override fun onPause() {
super.onPause()
fusedLocationProviderClient?.removeLocationUpdates(mLocationCallback)
}

private val mLocationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
locationResult.lastLocation
Log.d("MainActivity", "callback: $latitude $longitude")
locationChanged(locationResult.lastLocation)
latitude = locationResult.lastLocation.latitude
longitude = locationResult.lastLocation.longitude
binding.longitudeText.text = "Longitude: $longitude"
binding.latitudeText.text = "Latitude: $latitude"
}
}

private fun startLocationUpdates() {
mLocationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
mLocationRequest.interval = interval
mLocationRequest.fastestInterval = fastestInterval

val builder = LocationSettingsRequest.Builder()
builder.addLocationRequest(mLocationRequest)
val locationSettingsRequest = builder.build()
val settingsClient = LocationServices.getSettingsClient(this)
settingsClient.checkLocationSettings(locationSettingsRequest)

fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this)

if (ActivityCompat.checkSelfPermission(
this, Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
this, Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED) {
return
}
fusedLocationProviderClient!!.requestLocationUpdates(
mLocationRequest,
mLocationCallback,
Looper.myLooper()!!)
}

private fun checkForPermission(context: Context) {
if (context.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) ==
PackageManager.PERMISSION_GRANTED) {
return
} else {
ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION),
requestPermissionCode)
return
}
}

private fun showAlertMessage() {
val builder = AlertDialog.Builder(this)
builder.setMessage("The location permission is disabled. Do you want to enable it?")
.setCancelable(false)
.setPositiveButton("Yes") { _, _ ->
startActivityForResult(
Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
, 10)
}
.setNegativeButton("No") { dialog, _ ->
dialog.cancel()
finish()
}
val alert: AlertDialog = builder.create()
alert.show()
}

fun locationChanged(location: Location) {
mLastLocation = location
longitude = mLastLocation.longitude
latitude = mLastLocation.latitude
binding.longitudeText.text = "Longitude: $longitude"
binding.latitudeText.text = "Latitude: $latitude"
Log.d("MainActivity", "function: $latitude $longitude")
}

override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == requestPermissionCode) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startLocationUpdates()
} else {
Toast.makeText(this, "Permission Denied", Toast.LENGTH_SHORT).show()
}
}
}
}

Finished Product

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Alexander Portillo

Alexander Portillo

20 Years Old | Pursing Android Development