Get location android Kotlin
Asked Answered
C

8

37

I recently added get location function. When I try to show longitude and latitude, it returns zero.

This my LocationListener class:

inner class MylocationListener: LocationListener {
    constructor():super(){
        mylocation= Location("me")
        mylocation!!.longitude
        mylocation!!.latitude
    }

    override fun onLocationChanged(location: Location?) {
        mylocation=location
    }

    override fun onStatusChanged(p0: String?, p1: Int, p2: Bundle?) {}

    override fun onProviderEnabled(p0: String?) {}

    override fun onProviderDisabled(p0: String?) {}
}

And this my GetUserLocation function:

fun GetUserLocation(){
    var mylocation= MylocationListener()
    var locationManager=getSystemService(Context.LOCATION_SERVICE) as LocationManager
    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,0,0.1f,mylocation)
}

And this my function to return my longitude and latitude:

fun getLoction (view: View){
    prgDialog!!.show();

    GetUserLocation()

    button.setTextColor(getResources().getColor(R.color.green));
    textView.text = mylocation!!.latitude.toFloat().toString()
    Toast.makeText(this, mylocation!!.latitude.toFloat().toString(), Toast.LENGTH_LONG).show()
    Toast.makeText(this, mylocation!!.longitude.toFloat().toString(), Toast.LENGTH_LONG).show()

    prgDialog!!.hide()
} 
Chomp answered 30/8, 2017 at 10:39 Comment(2)
It returns zero or null?Dunsany
Have your application obtained required permissions for location? Do you test on device or emulator? Is gps active on on the device?Salience
M
32

When GetUserLocation returns, locationManager goes out of scope and presumably is destroyed, preventing onLocationChanged from being called and providing updates.

Also, you've defined mylocation inside of GetUserLocation so it also goes out of scope and further kills any chance or your getting an update.

You have not shown where and how the outer mylocation is declared (outside of GetUserLocation), but how ever it is declared, it is being shadowed by the one inside of GetUserLocation. So you aren't getting much.

Here is an example of how you might do it. (The variable thetext is defined within the layout xml and accessed with Kotlin extensions.)

// in the android manifest
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
// allow these through Appliation Manager if necessary

// inside a basic activity
private var locationManager : LocationManager? = null

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    setSupportActionBar(toolbar)

    // Create persistent LocationManager reference
    locationManager = getSystemService(LOCATION_SERVICE) as LocationManager?

    fab.setOnClickListener { view ->
        try {
            // Request location updates
            locationManager?.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0L, 0f, locationListener)
        } catch(ex: SecurityException) {
            Log.d("myTag", "Security Exception, no location available")
        }
    }
}

//define the listener
private val locationListener: LocationListener = object : LocationListener {
    override fun onLocationChanged(location: Location) {
        thetext.text = ("" + location.longitude + ":" + location.latitude)
    }
    override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {}
    override fun onProviderEnabled(provider: String) {}
    override fun onProviderDisabled(provider: String) {}
}
Mortmain answered 30/8, 2017 at 12:25 Comment(1)
For newer Android versions it's important to ask for the permissions, showing an explanation when needed. I had to do this for Camera, Storage and now Location, so I created an extension function, that could be helpful for someone else: github.com/JCarlosR/Redemnorte/blob/…Leclair
D
54

In 2019 Best Offical Solution in Kotlin

Google API Client/FusedLocationApi are deprecated and Location Manager is not useful at all. So Google prefer Fused Location Provider Using the Google Play services location APIs "FusedLocationProviderClient" is used to get location and its better way for battery saving and accuracy

Here is sample code in kotlin to get the last known location /one-time location( equivalent to the current location)

 // declare a global variable of FusedLocationProviderClient
    private lateinit var fusedLocationClient: FusedLocationProviderClient

// in onCreate() initialize FusedLocationProviderClient
    fusedLocationClient = LocationServices.getFusedLocationProviderClient(context!!)

 /**
     * call this method for receive location
     * get location and give callback when successfully retrieve
     * function itself check location permission before access related methods
     *
     */
    fun getLastKnownLocation() {
            fusedLocationClient.lastLocation
                .addOnSuccessListener { location->
                    if (location != null) {
                       // use your location object
                        // get latitude , longitude and other info from this
                    }

                }

    }

If your app can continuously track the location then you have to receive Receive location updates

Check the sample for that in kotlin

// declare a global variable FusedLocationProviderClient
        private lateinit var fusedLocationClient: FusedLocationProviderClient

    // in onCreate() initialize FusedLocationProviderClient
        fusedLocationClient = LocationServices.getFusedLocationProviderClient(context!!)


      // globally declare LocationRequest
        private lateinit var locationRequest: LocationRequest

        // globally declare LocationCallback    
        private lateinit var locationCallback: LocationCallback


        /**
         * call this method in onCreate
         * onLocationResult call when location is changed 
         */
        private fun getLocationUpdates()
        {

                fusedLocationClient = LocationServices.getFusedLocationProviderClient(context!!)
                locationRequest = LocationRequest()
                locationRequest.interval = 50000
                locationRequest.fastestInterval = 50000
                locationRequest.smallestDisplacement = 170f // 170 m = 0.1 mile
                locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY //set according to your app function
                locationCallback = object : LocationCallback() {
                    override fun onLocationResult(locationResult: LocationResult?) {
                        locationResult ?: return

                        if (locationResult.locations.isNotEmpty()) {
                            // get latest location 
                            val location =
                                locationResult.lastLocation
                            // use your location object
                            // get latitude , longitude and other info from this
                        }


                    }
                }
        }

        //start location updates
        private fun startLocationUpdates() {
            fusedLocationClient.requestLocationUpdates(
                locationRequest,
                locationCallback,
                null /* Looper */
            )
        }

        // stop location updates
        private fun stopLocationUpdates() {
            fusedLocationClient.removeLocationUpdates(locationCallback)
        }

        // stop receiving location update when activity not visible/foreground
        override fun onPause() {
            super.onPause()
            stopLocationUpdates()
        }

        // start receiving location update when activity  visible/foreground
        override fun onResume() {
            super.onResume()
            startLocationUpdates()
        }

Make sure you take care about Mainfaist permission and runtime permission for location

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

and for Gradle add this

implementation 'com.google.android.gms:play-services-location:17.0.0'

For more details follow these official documents

https://developer.android.com/training/location/retrieve-current

https://developer.android.com/training/location/receive-location-updates

https://developers.google.com/android/reference/com/google/android/gms/location/FusedLocationProviderClient

Diversify answered 12/8, 2019 at 19:49 Comment(7)
perfect answer! I would suggest using "locationResult.lastLocation" instead of getting value from 0th index.Cytoplast
don't forget to add logic for requesting Location permissions, or else you will need to remember to do it manually via app settingCiaphus
@Ciaphus yes run time permission are mandatory on 6.0(+) android marshmallow. I will add a note on my answer. Thank you very much for point outDiversify
LocationRequest() is deprecatedAvant
@SadiqueKhan, We can use LocationRequest.create() static method. StackOverflowUnderwing
LocationRequest.create() seems also deprecated. How odd.Epictetus
it asks to replace context!! to requireContext()Janiuszck
M
32

When GetUserLocation returns, locationManager goes out of scope and presumably is destroyed, preventing onLocationChanged from being called and providing updates.

Also, you've defined mylocation inside of GetUserLocation so it also goes out of scope and further kills any chance or your getting an update.

You have not shown where and how the outer mylocation is declared (outside of GetUserLocation), but how ever it is declared, it is being shadowed by the one inside of GetUserLocation. So you aren't getting much.

Here is an example of how you might do it. (The variable thetext is defined within the layout xml and accessed with Kotlin extensions.)

// in the android manifest
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
// allow these through Appliation Manager if necessary

// inside a basic activity
private var locationManager : LocationManager? = null

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    setSupportActionBar(toolbar)

    // Create persistent LocationManager reference
    locationManager = getSystemService(LOCATION_SERVICE) as LocationManager?

    fab.setOnClickListener { view ->
        try {
            // Request location updates
            locationManager?.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0L, 0f, locationListener)
        } catch(ex: SecurityException) {
            Log.d("myTag", "Security Exception, no location available")
        }
    }
}

//define the listener
private val locationListener: LocationListener = object : LocationListener {
    override fun onLocationChanged(location: Location) {
        thetext.text = ("" + location.longitude + ":" + location.latitude)
    }
    override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {}
    override fun onProviderEnabled(provider: String) {}
    override fun onProviderDisabled(provider: String) {}
}
Mortmain answered 30/8, 2017 at 12:25 Comment(1)
For newer Android versions it's important to ask for the permissions, showing an explanation when needed. I had to do this for Camera, Storage and now Location, so I created an extension function, that could be helpful for someone else: github.com/JCarlosR/Redemnorte/blob/…Leclair
S
16

I know it's late, but now Google has made it simpler to use. In the developer site, it says that you need to create a Client:

private lateinit var fusedLocationClient: FusedLocationProviderClient

Then onCreate get the provider:

override fun onCreate(savedInstanceState: Bundle?) {
    // ...
    fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
}

And finally, to get your last location just call:

//Don't forget to ask for permissions for ACCESS_COARSE_LOCATION 
//and ACCESS_FINE_LOCATION
@SuppressLint("MissingPermission")
private fun obtieneLocalizacion(){
    fusedLocationClient.lastLocation
            .addOnSuccessListener { location: Location? ->
                latitude =  location?.latitude
                longitude = location?.longitude
            }
}

*Tested with this implementation for location (Setup in your app gradle file)

implementation 'com.google.android.gms:play-services-location:15.0.1'

For more info, check this link:

Obtain last location

Saga answered 18/7, 2018 at 18:20 Comment(2)
on some devices when you switch the location OFF and then turn it back ON - the lastLocation will be nullDerail
this is always null if google maps or other apps that get location do not update fusedLocationClient.lastLocationJeannettajeannette
L
12

Get location with address in android kotlin

Add this line in dependencies

implementation 'com.google.android.gms:play-services-location:17.0.0'

Add this in AndroidManifest

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

Copy this below code in your class

class MainActivity : AppCompatActivity() {

private lateinit var fusedLocationClient: FusedLocationProviderClient
private lateinit var locationRequest: LocationRequest
private lateinit var locationCallback: LocationCallback

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_splash)
    /*Check location*/
    checkLocation()
}

private fun checkLocation(){
    val manager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
    if (!manager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
        showAlertLocation()
    }
    fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
    getLocationUpdates()
}

private fun showAlertLocation() {
    val dialog = AlertDialog.Builder(this)
    dialog.setMessage("Your location settings is set to Off, Please enable location to use this application")
    dialog.setPositiveButton("Settings") { _, _ ->
        val myIntent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
        startActivity(myIntent)
    }
    dialog.setNegativeButton("Cancel") { _, _ ->
        finish()
    }
    dialog.setCancelable(false)
    dialog.show()
}

private fun getLocationUpdates() {
    fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
    locationRequest = LocationRequest()
    locationRequest.interval = 50000
    locationRequest.fastestInterval = 50000
    locationRequest.smallestDisplacement = 170f //170 m = 0.1 mile
    locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY //according to your app
    locationCallback = object : LocationCallback() {
        override fun onLocationResult(locationResult: LocationResult?) {
            locationResult ?: return
            if (locationResult.locations.isNotEmpty()) {
                /*val location = locationResult.lastLocation
                Log.e("location", location.toString())*/
                val addresses: List<Address>?
                val geoCoder = Geocoder(applicationContext, Locale.getDefault())
                addresses = geoCoder.getFromLocation(
                    locationResult.lastLocation.latitude,
                    locationResult.lastLocation.longitude,
                    1
                )
                if (addresses != null && addresses.isNotEmpty()) {
                    val address: String = addresses[0].getAddressLine(0)
                    val city: String = addresses[0].locality
                    val state: String = addresses[0].adminArea
                    val country: String = addresses[0].countryName
                    val postalCode: String = addresses[0].postalCode
                    val knownName: String = addresses[0].featureName
                    Log.e("location", "$address $city $state $postalCode $country $knownName")
                }
            }
        }
    }
}

// Start location updates
private fun startLocationUpdates() {
    fusedLocationClient.requestLocationUpdates(
        locationRequest,
        locationCallback,
        null /* Looper */
    )
}

// Stop location updates
private fun stopLocationUpdates() {
    fusedLocationClient.removeLocationUpdates(locationCallback)
}

// Stop receiving location update when activity not visible/foreground
override fun onPause() {
    super.onPause()
    stopLocationUpdates()
}

// Start receiving location update when activity  visible/foreground
override fun onResume() {
    super.onResume()
    startLocationUpdates()
}}

Run your code and check the log, Happy Coding

Laquanda answered 21/1, 2020 at 15:14 Comment(0)
S
11

I read many of answers but question is get only last known location. With receiver it continuously send latitude and longitude I have solution for this in kotlin.. Give permissions

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




    public fun getLastKnownLocation(context: Context) {
        val locationManager: LocationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
        val providers: List<String> = locationManager.getProviders(true)
        var location: Location? = null
        for (i in providers.size - 1 downTo 0) {
            location= locationManager.getLastKnownLocation(providers[i])
            if (location != null)
                break
        }
        val gps = DoubleArray(2)
        if (location != null) {
            gps[0] = location.getLatitude()
            gps[1] = location.getLongitude()
            Log.e("gpsLat",gps[0].toString())
            Log.e("gpsLong",gps[1].toString())

        }

    }
Shoreless answered 30/3, 2020 at 9:48 Comment(1)
Only code that got me anywhere...Toshikotoss
L
5

I would like to help someone who is trying to get location from scratch. Here is the reference: Kotlin Get Current Location

Code will first check whether location is on or off in device and then will fetch latitude and longitudes and will update it constantly.

In build.gradle(Module:app) file put this

compile 'com.google.android.gms:play-services:11.8.0'

activity_main.xml code

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_marginTop="10dp"
    android:layout_marginLeft="10dp"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/latitude"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:text="Latitude:"
        android:textSize="18sp" />
    <TextView
        android:id="@+id/latitude_textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/latitude"
        android:layout_marginLeft="10dp"
        android:layout_toRightOf="@+id/latitude"
        android:textSize="16sp" />
    <TextView
        android:id="@+id/longitude"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:text="Longitude:"
        android:layout_marginTop="24dp"
        android:textSize="18sp" />
    <TextView
        android:id="@+id/longitude_textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/longitude"
        android:layout_marginLeft="10dp"
        android:layout_toRightOf="@+id/longitude"
        android:textSize="16sp"/>

</RelativeLayout>

MainActivity.kt

import android.Manifest
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.location.Location
import android.location.LocationManager
import android.provider.Settings
import android.support.v4.app.ActivityCompat
import android.support.v7.app.AlertDialog
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.TextView
import android.widget.Toast
import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.api.GoogleApiClient
import com.google.android.gms.location.LocationRequest
import com.google.android.gms.location.LocationServices
import com.google.android.gms.maps.model.LatLng

class MainActivity : AppCompatActivity(), GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, com.google.android.gms.location.LocationListener {

    private var mLatitudeTextView: TextView? = null
    private var mLongitudeTextView: TextView? = null
    private var mGoogleApiClient: GoogleApiClient? = null
    private var mLocation: Location? = null
    private var mLocationManager: LocationManager? = null

    private var mLocationRequest: LocationRequest? = null
    private val listener: com.google.android.gms.location.LocationListener? = null
    private val UPDATE_INTERVAL = (2 * 1000).toLong()  /* 10 secs */
    private val FASTEST_INTERVAL: Long = 2000 /* 2 sec */

    private var locationManager: LocationManager? = null

    private val isLocationEnabled: Boolean
        get() {
            locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
            return locationManager!!.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager!!.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
        }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        mLatitudeTextView = findViewById(R.id.latitude_textview) as TextView
        mLongitudeTextView = findViewById(R.id.longitude_textview) as TextView

        mGoogleApiClient = GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build()

        mLocationManager = this.getSystemService(Context.LOCATION_SERVICE) as LocationManager

        Log.d("gggg","uooo");
        checkLocation() //check whether location service is enable or not in your  phone
    }

    @SuppressLint("MissingPermission")
    override fun onConnected(p0: Bundle?) {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // TODO: Consider calling
            //    ActivityCompat#requestPermissions
            // here to request the missing permissions, and then overriding
            //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
            //                                          int[] grantResults)
            // to handle the case where the user grants the permission. See the documentation
            // for ActivityCompat#requestPermissions for more details.
            return
        }

        startLocationUpdates()

        mLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient)

        if (mLocation == null) {
            startLocationUpdates()
        }
        if (mLocation != null) {

            // mLatitudeTextView.setText(String.valueOf(mLocation.getLatitude()));
            //mLongitudeTextView.setText(String.valueOf(mLocation.getLongitude()));
        } else {
            Toast.makeText(this, "Location not Detected", Toast.LENGTH_SHORT).show()
        }
    }

    override fun onConnectionSuspended(i: Int) {
        Log.i(TAG, "Connection Suspended")
        mGoogleApiClient!!.connect()
    }

    override fun onConnectionFailed(connectionResult: ConnectionResult) {
        Log.i(TAG, "Connection failed. Error: " + connectionResult.getErrorCode())
    }

    override fun onStart() {
        super.onStart()
        if (mGoogleApiClient != null) {
            mGoogleApiClient!!.connect()
        }
    }

    override fun onStop() {
        super.onStop()
        if (mGoogleApiClient!!.isConnected()) {
            mGoogleApiClient!!.disconnect()
        }
    }

    @SuppressLint("MissingPermission")
    protected fun startLocationUpdates() {
        // Create the location request
        mLocationRequest = LocationRequest.create()
                .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
                .setInterval(UPDATE_INTERVAL)
                .setFastestInterval(FASTEST_INTERVAL)
        // Request location updates
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // TODO: Consider calling
            //    ActivityCompat#requestPermissions
            // here to request the missing permissions, and then overriding
            //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
            //                                          int[] grantResults)
            // to handle the case where the user grants the permission. See the documentation
            // for ActivityCompat#requestPermissions for more details.
            return
        }
        LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
                mLocationRequest, this)
        Log.d("reque", "--->>>>")
    }

    override fun onLocationChanged(location: Location) {

        val msg = "Updated Location: " +
                java.lang.Double.toString(location.latitude) + "," +
                java.lang.Double.toString(location.longitude)
        mLatitudeTextView!!.text = location.latitude.toString()
        mLongitudeTextView!!.text = location.longitude.toString()
        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
        // You can now create a LatLng Object for use with maps
        val latLng = LatLng(location.latitude, location.longitude)
    }

    private fun checkLocation(): Boolean {
        if (!isLocationEnabled)
            showAlert()
        return isLocationEnabled
    }

    private fun showAlert() {
        val dialog = AlertDialog.Builder(this)
        dialog.setTitle("Enable Location")
                .setMessage("Your Locations Settings is set to 'Off'.\nPlease Enable Location to " + "use this app")
                .setPositiveButton("Location Settings") { paramDialogInterface, paramInt ->
                    val myIntent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
                    startActivity(myIntent)
                }
                .setNegativeButton("Cancel") { paramDialogInterface, paramInt -> }
        dialog.show()
    }

    companion object {

        private val TAG = "MainActivity"
    }

}
Leoraleos answered 8/5, 2018 at 6:20 Comment(1)
was looking for this for days ! Thanks a lot !Hawse
Y
3

gradle(Module: appname.app)

buildFeatures{
    viewBinding true
} // for databinding
dependencies{
implementation 'com.google.android.gms:play-services-location:18.0.0'
}

manifest:

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

activity:

class Updateposition : AppCompatActivity() { 

private lateinit var bind: ActivityUpdatepositionBinding
private lateinit var fusedLocationProviderClient: FusedLocationProviderClient

//private lateinit var lat: String // :Double
//private lateinit var long: String // ||.toDouble


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

    //supportActionBar!!.hide()
    fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this)



    try {

        getActualLocation()
        //getActualLocation() 
        //getActualLocation()



       
       

    }catch (e: java.lang.Exception){

        e.printStackTrace()

    }
}

private fun getActualLocation() {

    val task = fusedLocationProviderClient.lastLocation

    if (ActivityCompat
            .checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION)
        != PackageManager.PERMISSION_GRANTED && ActivityCompat
            .checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION)
        != PackageManager.PERMISSION_GRANTED){
            
        ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION), 101)
        return
    }

    task.addOnSuccessListener {
        if (it != null){
            bind.tvLatitude.text = "${it.latitude}" // it.longitude is a Double
            bind.tvLongitude.text = "${it.longitude}" // tvLongitude is a TextView

        }
    }
}// one curly brace could be missing (or not)

run it then close your app then run again and voila!

Yeo answered 19/2, 2022 at 0:24 Comment(2)
sad for 0 upvotes. +1 Worked like a charm!Amund
Now just need to find how to store latitude and longitude in a variableYeo
H
1

May 2023 updated version to get continuous location updates.

I initially set the locationCallback and locationListener as optional types because some people may want to use one, and other people the other, so I created the code for both of them. Either one is called at the bottom of the else condition in getLocationUpdates()

Because of this choice I also set LocationRequest as an optional type.

If you get errors, you might need to put @RequiresApi(Build.VERSION_CODES.TIRAMISU) above each function or outside the class as I did below for simplicity.

Add these to Manifest:

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

MainActivity:

import android.content.Context
import android.content.Intent
import android.location.*
import com.google.android.gms.location.LocationRequest
import com.google.android.gms.location.LocationListener
import android.os.Build
import android.os.Looper
import androidx.annotation.RequiresApi
import com.google.android.gms.location.*
import java.util.*
import android.provider.Settings

@RequiresApi(Build.VERSION_CODES.TIRAMISU) // *** This might not be necessary depending on which SDK version you're using. Also, this should really go above EACH FUNCTION, NOT outside the class ***
class MainActivity : AppCompatActivity() {

    // region - Properties
    private var fusedLocationClient: FusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this.applicationContext)
    private var locationRequest: LocationRequest? = null
    private var locationCallback: LocationCallback? = null
    private var locationListener: LocationListener? = null
    // endregion

    // region - Lifecycle
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        getLocationUpdates() // <--- LocationRequest set in here
    }

    override fun onResume() {
        super.onResume()
        startLocationUpdates()
    }

    override fun onPause() {
        super.onPause()
        stopLocationUpdates()
    }
    // endregion

    // region - Permissions, LocationRequest, and set LocationCallback OR LocationListener
    private fun getLocationUpdates() {

        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
            != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
            != PackageManager.PERMISSION_GRANTED
        ) {

            ActivityCompat.requestPermissions(
                this, arrayOf(
                    Manifest.permission.ACCESS_FINE_LOCATION
                ),
                1
            )
        } else {

            setLocationRequest()

            setLocationCallback() // <---CALL HERE, but comment out setLocationListener()

            //setLocationListener() // <---CALL HERE, but comment out setLocationCallback()
        }
    }

    private fun setLocationRequest() {

        locationRequest = LocationRequest.Builder(1000L).apply {
            this.setGranularity(Priority.PRIORITY_HIGH_ACCURACY)
            //this.setMinUpdateDistanceMeters(your_choice)
            //this.setMaxUpdateDelayMillis(your_choice)
            //this.setMinUpdateIntervalMillis(your_choice)
        }.build()
    }
    // endregion

    // region - Create LocationCallback / LocationListener
    private fun setLocationCallback() {

        locationCallback = object : LocationCallback() {
            override fun onLocationResult(locationResult: LocationResult) {
                for (location in locationResult.locations) {
                    parseLocationWithGeocoder(location)
                }
            }
        }
    }
    
    private fun setLocationListener() {

        locationListener = object : LocationListener {
            override fun onLocationChanged(location: Location) {
                parseLocationWithGeocoder(location)
            }
        }
    }
    // endregion

    // region - Start/Stop Location Updates
    private fun startLocationUpdates() {
        val locationRequest = locationRequest ?: return

        locationCallback?.let { callback ->
            fusedLocationClient.requestLocationUpdates(locationRequest, callback, Looper.getMainLooper())
        }

        locationListener?.let { listener ->
            fusedLocationClient.requestLocationUpdates(locationRequest, listener, Looper.getMainLooper())
        }
    }

    private fun stopLocationUpdates() {

        locationCallback?.let { callback ->
            fusedLocationClient.removeLocationUpdates(callback)
        }

        locationListener?.let { listener ->
            fusedLocationClient.removeLocationUpdates(listener)
        }
    }
    // endregion

    // region - GeoCoder Location Parsing
    private fun parseLocationWithGeocoder(location: Location) {

        val geoCoder = Geocoder(this.applicationContext, Locale.getDefault())
        geoCoder.getFromLocation(
            location.latitude,
            location.longitude,
            1,
            object : Geocoder.GeocodeListener {
                override fun onGeocode(addresses: MutableList<Address>) {

                    if (addresses.isNotEmpty()) {
                        val address: String = addresses[0].getAddressLine(0)
                        val city: String = addresses[0].locality
                        val state: String = addresses[0].adminArea
                        val country: String = addresses[0].countryName
                        val postalCode: String = addresses[0].postalCode
                        val knownName: String = addresses[0].featureName
                        println("address: $address | city: $city | state: $state | country: $country | zipCode: $postalCode | knownName: $knownName")
                    
                    } else {
                        println("Location Unavailable")
                    }
                }

                override fun onError(errorMessage: String?) {
                    super.onError(errorMessage)
                }
            })
    }
    // endregion
}

In addition, you should read these answers to handle Permission.DENIED or a location permission dialog not appearing. Seems to be either device version and/or sdk issues.

Hebraize answered 31/5, 2023 at 22:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.