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!
