Home Tutorials Hints & Tips

Android Location Services in Kotlin Part 3 - Dynamic Updates with the FusedLocationProvider

In this easy to follow three part series, we look at how to code Android location based services in Kotlin using the Fused Location Provider Client. In this part we will show you how to get dynamic location updates using the FusedLocationProvider.


In part 2, we looked at how the get the last known location of the device and deal with the runtime permissions.


We first need to create three Kotlin variables.


private var locationRequest: LocationRequest? = null

private var locationCallback: LocationCallback? = Null

private var updatesOn = false


The locationRequest variable is needed to configure parameters for the Fused Location Provider such as the interval we will access the location sensors.


The locationCallback used for receiving notifications from the Fused Location Provider when the device location has changed or can no longer be determined.


Finally, we will set a boolean flag to indicate whether location updates are turned on or off.


The next task is to configure the locationRequest:


locationRequest = LocationRequest()

locationRequest!!.interval = 7500

locationRequest!!.fastestInterval = 5000

locationRequest!!.priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY


First, set locationRequest as an object of the LocationRequest class. We then set the interval by which we wish to acquire the location from the Fused Location Provider. Here, I set the interval to 7500ms to speed up testing. However, the shorter the interval the more battery power will be used and so a value of 10000 to 15000ms may be better for a real app. We can also set a fastest interval. If set, our app can check to see if another app has generated a location that we can use. This consumes no power and so the interval can be much shorter. A period of about 5000ms is about right. We also need to set an initial locationRequest priority. The setPriority method defines the type of sensor used. Balanced Power Accuracy means that the location will be found by using WiFi and Cell Tower triangleization. PRIORITY_HIGH_ACCURACY uses the GPS but also uses more battery power than WiFi and Cell Tower triangleization. We can also go onto add setPriority code into the setOnClickListenser function for the tbGps_Balanced ToggleButton.


tbGps_Balanced.setOnClickListener {

   if (tbGps_Balanced.isChecked) {

      //using GPS only

      tvSensor.text = "GPS"

      locationRequest!!.priority = LocationRequest.PRIORITY_HIGH_ACCURACY

   } else {

      //using balanced power accuracy

      tvSensor.text = "Cell Tower and WiFi"

      locationRequest!!.priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY

   }

}


The next task is to create to location Callback. This is coded in the onCreate method and will be called each time the location changes. We need to override the onLocationResult method and we will simply update the User Interface (UI) with the location. The UI update code can be copied from the code block within the onSuccess listener from part 4.


locationCallback = object : LocationCallback() {

   override fun onLocationResult(p0: LocationResult?) {

   super.onLocationResult(p0)

      for (location in p0!!.locations) {

      if (location != null) {

         //update UI

         tvLatitude.text = location.latitude.toString()

         tvLongitude.text = location.longitude.toString()

         if (location.hasAccuracy()) {

            tvAccuracy.text = location.accuracy.toString()

         } else {

            tvAccuracy.text = "No Accuracy Available"

         }

         if (location.hasAltitude()) {

            tvAltitude.text = location.altitude.toString()

         } else {

            tvAltitude.text = "No Altitude Available"

         }

         if (location.hasSpeed()) {

            tvSpeed.text = location.speed.toString()

         } else {

            tvSpeed.text = "No Speed Available"

         }

      }

   }

}


We can then add code to turn on and turn off the location updates. We do not want any app to request updates in a pause state. This is bad practice. Therefore, we can use the Android Activity Lifecycle to turn location update on and off in the appropriate state. The diagram below shows the Android Activity Lifecycle.

The Android Activity Lifecycle


You will see that onResume is called after onCreate and also when the app is resumed. It makes sense to turn on location updates here. Also onPause is called before the app is paused and stopped. Therefore, it makes sense to stop the location updates here.


When overriding the onResume function, we need to check that location updates are enabled via the toggle button and if so, start the updates. We can create a function to do this:


override fun onResume() {

   super.onResume()

   if (updatesOn) startLocationUpdates()

}


We will stop the location updates by overriding the onPause function.


override fun onPause() {

   super.onPause()

   stopLocationUpdates()

}


The function startLocationUpdates is below:


private fun startLocationUpdates() {

   if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {

       fusedLocationProviderClient!!.requestLocationUpdates(locationRequest, locationCallback, null)

   } else {

      //request permissions

      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

          requestPermissions(arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION), MY_PERMISSION_FINE_LOCATION)

      }

   }

}


Location updates are enabled with the following command:


fusedLocationProviderClient!!.requestLocationUpdates(locationRequest, locationCallback, null)


It will need a permission check and we can simply reuse the code from part 2. The locationRequest and locationCallback are passed to the requestLocationUpdates method. The final parameter is the looper and this is set to null to ensure updates are run on the current thread.


The function stopLocationUpdates is below:


private fun stopLocationUpdates() {

    fusedLocationProviderClient!!.removeLocationUpdates(locationCallback)

}


The startLocationUpdates and stopLocationUpdates functions need to be added to the tbLocationOnOff onClickListener method. Also add code here to set the updatesOn Boolean flag to true or false.


tbLocationOnOff.setOnClickListener {

   if (tbLocationOnOff.isChecked) {

      //location update on

      tvUpdates.text = "On"

      updatesOn = true

      startLocationUpdates()

   } else {

      //location update off

      tvUpdates.text = "Off"

      updatesOn = false

      stopLocationUpdates()

   }

}


This is all the coding needed for part 4 and a screenshot of the output is below:


Android Kotlin Location Updates



After this tutorial your MainActivity.kt file should look like the one below:




Download Download project files

Privacy and Cookies Disclaimer Copyright
© 2015 - 2018 North Border Tech Training All rights reserved