Many of the android applications we uses in daily life needs users current locations continuously, Here we are going to implement LocationListener with Kotlin using FusedLocationProviderClient . We have previously used FusedLocationProviderApi which is deprecated now.
Add the permissions & Dependency
To access the location from the device add the following permissions to the manifest.xml file .
<uses-permission android:name=”android.permission.ACCESS_COARSE_LOCATION”/>
<uses-permission android:name=”android.permission.ACCESS_FINE_LOCATION”/>
Add the following dependencies into app level build.gradle ( Module:app) file.
implementation ‘com.google.android.gms:play-services-location:16.0.0’
Setup the Layout file
Setup layout file for our home screen. It has two Buttons and three TextViews as shown below
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
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">
<Button
android:id="@+id/btn_start_upds"
android:layout_width="match_parent"
android:layout_marginRight="12dp"
android:layout_marginLeft="12dp"
android:layout_marginTop="24dp"
android:layout_height="wrap_content"
android:text="Start Location UPDates" />
<Button
android:enabled="false"
android:id="@+id/btn_stop_upds"
android:layout_width="match_parent"
android:layout_marginRight="12dp"
android:layout_marginLeft="12dp"
android:layout_height="wrap_content"
android:text="Stop Location UPDates" />
<TextView
android:padding="12dp"
android:layout_marginTop="12dp"
android:textSize="18sp"
android:layout_marginRight="12dp"
android:layout_marginLeft="12dp"
android:layout_width="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_height="wrap_content"
android:id="@+id/txtLat"
/>
<TextView
android:padding="12dp"
android:layout_gravity="center_horizontal"
android:textSize="18sp"
android:layout_marginRight="12dp"
android:layout_marginLeft="12dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/txtLong"
/>
<TextView
android:layout_gravity="center_horizontal"
android:padding="12dp"
android:textSize="18sp"
android:layout_marginRight="12dp"
android:layout_marginLeft="12dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/txtTime" />
</LinearLayout>
Setup the MainActivity
Here we are going to learn how to implement location Listener in our MainActivity.kt Class with all details.
First we have to initialize
Check Permissions
From android version 6 (Marshmallow ) user have to accept all the permissions in run time. So we have to check whether used accepted all the permissions needed in run time .
We have added the permissions in
fun checkPermissionForLocation(context: Context): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (context.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) ==
PackageManager.PERMISSION_GRANTED){
true
}else{
// Show the permission request
ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION),
REQUEST_PERMISSION_LOCATION)
false
}
} else {
true
}
}
Now we have to implement onRequestPermissionsResult method to check if the permission is granted or not by the user.
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
if (requestCode == REQUEST_PERMISSION_LOCATION) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//We have to add startlocationUpdate() method later instead of Toast
Toast.makeText(this,"Permission granted",Toast.LENGTH_SHORT).show()
}
}
}
Check Location is ON
To check location is on we have to add the following code to our project.
private fun buildAlertMessageNoGps() {
val builder = AlertDialog.Builder(this)
builder.setMessage("Your GPS seems to be disabled, do you want to enable it?")
.setCancelable(false)
.setPositiveButton("Yes") { dialog, id ->
startActivityForResult(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
, 11)
}
.setNegativeButton("No") { dialog, id ->
dialog.cancel()
finish()
}
val alert: AlertDialog = builder.create()
alert.show()
}
Setup LocationListener
Now we are going to setup the LocationListener using startLocationUpdates() method. Before that we have to add a LocationCallback as given below.
private val mLocationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
// do work here
locationResult.lastLocation
onLocationChanged(locationResult.lastLocation)
}
}
fun onLocationChanged(location: Location) {
// New location has now been determined
mLastLocation = location
if (mLastLocation != null) {
// Update the UI from here
}
}
Now Add startLocationUpdates() method to your code as follows
protected fun startLocationUpdates() {
// Create the location request to start receiving updates
mLocationRequest = LocationRequest()
mLocationRequest!!.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
mLocationRequest!!.setInterval(INTERVAL)
mLocationRequest!!.setFastestInterval(FASTEST_INTERVAL)
// Create LocationSettingsRequest object using location request
val builder = LocationSettingsRequest.Builder()
builder.addLocationRequest(mLocationRequest!!)
val locationSettingsRequest = builder.build()
val settingsClient = LocationServices.getSettingsClient(this)
settingsClient.checkLocationSettings(locationSettingsRequest)
mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this)
// new Google API SDK v11 uses 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
}
mFusedLocationProviderClient!!.requestLocationUpdates(mLocationRequest, mLocationCallback,
Looper.myLooper())
}
To Stop Location Updates add the following
private fun stoplocationUpdates() {
mFusedLocationProviderClient!!.removeLocationUpdates(mLocationCallback)
}
Now we are all set to run the project. Please find the Complete code for MainActivity.kt file below.
MainActivity.kt
package com.kotlincodes.locationlistenerwithkotlin
import android.Manifest
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.location.Location
import android.location.LocationManager
import android.os.Build
import android.os.Bundle
import android.os.Looper
import android.provider.Settings
import android.support.v4.app.ActivityCompat
import android.support.v7.app.AlertDialog
import android.support.v7.app.AppCompatActivity
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import com.google.android.gms.location.*
import java.text.SimpleDateFormat
import java.util.*
class MainActivity : AppCompatActivity() {
private var mFusedLocationProviderClient: FusedLocationProviderClient? = null
private val INTERVAL: Long = 2000
private val FASTEST_INTERVAL: Long = 1000
lateinit var mLastLocation: Location
internal lateinit var mLocationRequest: LocationRequest
private val REQUEST_PERMISSION_LOCATION = 10
lateinit var btnStartupdate: Button
lateinit var btnStopUpdates: Button
lateinit var txtLat: TextView
lateinit var txtLong: TextView
lateinit var txtTime: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mLocationRequest = LocationRequest()
btnStartupdate = findViewById(R.id.btn_start_upds)
btnStopUpdates = findViewById(R.id.btn_stop_upds)
txtLat = findViewById(R.id.txtLat);
txtLong = findViewById(R.id.txtLong);
txtTime = findViewById(R.id.txtTime);
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
buildAlertMessageNoGps()
}
btnStartupdate.setOnClickListener {
if (checkPermissionForLocation(this)) {
startLocationUpdates()
btnStartupdate.isEnabled = false
btnStopUpdates.isEnabled = true
}
}
btnStopUpdates.setOnClickListener {
stoplocationUpdates()
txtTime.text = "Updates Stoped"
btnStartupdate.isEnabled = true
btnStopUpdates.isEnabled = false
}
}
private fun buildAlertMessageNoGps() {
val builder = AlertDialog.Builder(this)
builder.setMessage("Your GPS seems to be disabled, do you want to enable it?")
.setCancelable(false)
.setPositiveButton("Yes") { dialog, id ->
startActivityForResult(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
, 11)
}
.setNegativeButton("No") { dialog, id ->
dialog.cancel()
finish()
}
val alert: AlertDialog = builder.create()
alert.show()
}
protected fun startLocationUpdates() {
// Create the location request to start receiving updates
mLocationRequest!!.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
mLocationRequest!!.setInterval(INTERVAL)
mLocationRequest!!.setFastestInterval(FASTEST_INTERVAL)
// Create LocationSettingsRequest object using location request
val builder = LocationSettingsRequest.Builder()
builder.addLocationRequest(mLocationRequest!!)
val locationSettingsRequest = builder.build()
val settingsClient = LocationServices.getSettingsClient(this)
settingsClient.checkLocationSettings(locationSettingsRequest)
mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this)
// new Google API SDK v11 uses 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
}
mFusedLocationProviderClient!!.requestLocationUpdates(mLocationRequest, mLocationCallback,
Looper.myLooper())
}
private val mLocationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
// do work here
locationResult.lastLocation
onLocationChanged(locationResult.lastLocation)
}
}
fun onLocationChanged(location: Location) {
// New location has now been determined
mLastLocation = location
val date: Date = Calendar.getInstance().time
val sdf = SimpleDateFormat("hh:mm:ss a")
txtTime.text = "Updated at : " + sdf.format(date)
txtLat.text = "LATITUDE : " + mLastLocation.latitude
txtLong.text = "LONGITUDE : " + mLastLocation.longitude
// You can now create a LatLng Object for use with maps
}
private fun stoplocationUpdates() {
mFusedLocationProviderClient!!.removeLocationUpdates(mLocationCallback)
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
if (requestCode == REQUEST_PERMISSION_LOCATION) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startLocationUpdates()
btnStartupdate.isEnabled = false
btnStopUpdates.isEnabled = true
} else {
Toast.makeText(this@MainActivity, "Permission Denied", Toast.LENGTH_SHORT).show()
}
}
}
fun checkPermissionForLocation(context: Context): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (context.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) ==
PackageManager.PERMISSION_GRANTED) {
true
} else {
// Show the permission request
ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION),
REQUEST_PERMISSION_LOCATION)
false
}
} else {
true
}
}
}
That’s it! Now run the project!
The full source code is available here.
Thanks for reading!
