获取安卓位置信息 Kotlin

34

我最近添加了获取位置功能。当我尝试展示经度和纬度时,它返回0。

这是我的LocationListener类:

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?) {}
}

这是我的 GetUSerLocation 函数:

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

这是我的函数来返回我的经度和纬度:

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()
} 

它返回零还是空值? - Stanislav Bondar
你的应用程序已经获取了位置所需的权限吗?你是在设备上还是模拟器上进行测试?设备上的 GPS 是否处于活动状态? - Josef Adamcik
8个回答

53

2019年最佳官方Kotlin解决方案

Google API客户端/FusedLocationApi已过时,而位置管理器完全无用。因此,Google更喜欢使用Google Play服务位置API中的融合位置提供程序“FusedLocationProviderClient”来获取位置,这是一种更好的节省电池和提高准确性的方式。

以下是在Kotlin中获取上次已知位置/一次性位置(相当于当前位置)的示例代码:

 // 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
                    }

                }

    }

如果您的应用程序可以持续跟踪位置,则必须接收位置更新。

在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()
        }

确保您在位置方面关心Mainfaist权限和运行时权限

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

对于Gradle,请添加以下内容

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

了解更多详细信息,请参考以下官方文件:

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


1
完美的答案!我建议使用“locationResult.lastLocation”而不是从第0个索引获取值。 - ShadeToD
不要忘记添加请求位置权限的逻辑,否则您将需要通过应用程序设置手动执行。 - lasec0203
@lasec0203 是的,在6.0(+)安卓棉花糖版本中,运行时权限是必需的。我会在我的回答中添加一条注释。非常感谢您指出。 - Mayank Sharma
LocationRequest() 已过时。 - Sadique Khan
1
@SadiqueKhan,我们可以使用LocationRequest.create()静态方法。StackOverflow - Yogi
LocationRequest.create() 似乎也已经过时了。真奇怪。 - Houman

32
GetUserLocation返回时,locationManager超出了作用域并可能被销毁,防止调用onLocationChanged和提供更新。
此外,您已经在GetUserLocation内定义了mylocation,因此它也会超出作用域并进一步破坏您获取更新的任何机会。
您没有展示外部mylocation是如何声明的(在GetUserLocation之外),但无论如何声明,它都被GetUserLocation内部的一个遮蔽。所以你得不到太多。
以下是一个示例,说明您可能会如何做。(变量thetext在布局xml中定义,并使用Kotlin扩展访问。)
// 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) {}
}

4
对于较新的Android版本,请求权限并在需要时显示解释非常重要。我已经为相机、存储和现在的位置做了这个操作,因此我创建了一个扩展函数,对其他人可能有所帮助:https://github.com/JCarlosR/Redemnorte/blob/80e82dd9795e945ca093d08a9194656971f07485/app/src/main/java/com/youtube/sorcjc/redemnorte/util/ActivityExtensions.kt#L8 - JCarlosR

16
我知道现在有点晚了,但是Google已经让使用变得更加简单。在开发者网站上,它说你需要创建一个客户端:
private lateinit var fusedLocationClient: FusedLocationProviderClient

然后在onCreate方法中获取提供者:

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

最后,要获取您的最后位置,只需调用:

//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
            }
}

*使用此实现进行位置测试(在您的应用程序gradle文件中设置)

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

更多信息请查看此链接:

获取最后位置


1
在某些设备上,当您关闭位置服务然后重新打开时,lastLocation会变为空值。 - Edhar Khimich
如果Google地图或其他获取位置的应用程序不更新fusedLocationClient.lastLocation,则始终为空。 - Giuseppe Garassino

12
在Android Kotlin中使用地址获取位置

在依赖项中添加以下行

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

在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" />

将下面的代码复制到你的类中

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()
}}

运行您的代码并检查日志,编程愉快


11

我阅读了许多答案,但问题只是获取最后已知位置。使用接收器可以持续发送纬度和经度。我在Kotlin中有解决方案...请授予权限。


<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())

        }

    }

只有这段代码让我有所进展... - nayriz

5

我希望能帮助那些从零开始尝试获取位置信息的人。

这里是参考资料:Kotlin获取当前位置

代码首先会检查设备的位置是否打开,然后会不断地获取经度和纬度并更新它。

在build.gradle(Module:app)文件中添加以下内容:

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

activity_main.xml 代码

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

}

找了好几天终于找到了!非常感谢! - Lilo

3

gradle(Module: appname.app)

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

清单:

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

活动:

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)

运行它,然后关闭你的应用程序,再次运行即可!

1
0个赞让我感到难过。+1,完美地解决了问题! - devDeejay
现在只需要找到如何将纬度和经度存储在变量中。 - MarkT

1

2023年5月更新版,以获得持续位置更新。

我最初将locationCallbacklocationListener设置为可选类型,因为有些人可能想使用其中一个,而其他人可能想使用另一个,所以我为两者都创建了代码。其中任何一个都在getLocationUpdates()的else条件底部调用。

由于这个选择,我还将LocationRequest设置为可选类型。

如果您遇到错误,您可能需要将@RequiresApi(Build.VERSION_CODES.TIRAMISU)放在每个函数上面或放在类外面,就像我下面简单说明的那样。

将以下内容添加到清单:

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

主活动:

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
}

此外,您应该阅读这些答案来处理Permission.DENIED或位置permission dialognot appearing。似乎是设备版本和/或SDK问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接