You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

2023年Kotlin获取用户当前地址的更佳方案咨询

2023年Kotlin实现更可靠的用户定位方案(替代lastLocation)

fusedLocationClient.lastLocation的问题很明确:它优先返回缓存的位置数据,要是没有缓存就直接返回null,而且完全不保证数据的新鲜度,这就是你觉得它慢或者失效的核心原因。2023年更推荐使用getCurrentLocation()方法,这是Google Play Services Location库提供的更可靠的方案,专门用来获取实时的当前位置。

核心方案步骤

1. 确保依赖版本

在Module级别的build.gradle中引入2023年稳定版的定位库:

dependencies {
    implementation 'com.google.android.gms:play-services-location:21.0.1'
}

2. 权限准备

先在AndroidManifest.xml中声明必要权限:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- Android 12+ 如需前台定位通知,添加以下权限 -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

注意:Android 6.0+需要动态请求ACCESS_FINE_LOCATION权限,按钮触发定位前一定要先检查权限状态。

3. 用Kotlin协程实现定位逻辑

结合协程能更优雅地处理异步请求,避免回调嵌套:

import android.Manifest
import android.content.pm.PackageManager
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import com.google.android.gms.location.CurrentLocationRequest
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationServices
import com.google.android.gms.tasks.CancellationTokenSource
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.tasks.await
import java.util.Locale

class LocationActivity : AppCompatActivity() {
    private lateinit var fusedLocationClient: FusedLocationProviderClient
    private lateinit var locationBtn: Button
    private lateinit var addressTv: TextView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_location)
        
        fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
        locationBtn = findViewById(R.id.btn_get_location)
        addressTv = findViewById(R.id.tv_address)

        locationBtn.setOnClickListener {
            CoroutineScope(Dispatchers.Main).launch {
                getCurrentLocationAndAddress()
            }
        }
    }

    private suspend fun getCurrentLocationAndAddress() {
        // 检查权限
        if (ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.ACCESS_FINE_LOCATION
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            // 请求权限
            ActivityCompat.requestPermissions(
                this,
                arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
                1001
            )
            return
        }

        // 创建当前位置请求,设置优先级和超时
        val currentLocationRequest = CurrentLocationRequest.Builder()
            .setPriority(CurrentLocationRequest.PRIORITY_HIGH_ACCURACY)
            .setDurationMillis(10000) // 10秒超时
            .setMaxUpdateAgeMillis(0) // 不接受缓存数据,必须实时获取
            .build()

        val cancellationTokenSource = CancellationTokenSource()

        try {
            // 获取实时位置
            val location = fusedLocationClient.getCurrentLocation(
                currentLocationRequest,
                cancellationTokenSource.token
            ).await()

            location?.let {
                // 解析地址
                val address = getAddressFromLocation(it.latitude, it.longitude)
                addressTv.text = address ?: "无法解析地址"
            } ?: run {
                addressTv.text = "无法获取当前位置"
            }
        } catch (e: Exception) {
            addressTv.text = "定位失败:${e.message}"
        }
    }

    private fun getAddressFromLocation(lat: Double, lng: Double): String? {
        val geocoder = android.location.Geocoder(this, Locale.getDefault())
        return try {
            val addresses = geocoder.getFromLocation(lat, lng, 1)
            addresses?.firstOrNull()?.run {
                "${getAddressLine(0)}, ${locality}, ${countryName}"
            }
        } catch (e: Exception) {
            null
        }
    }

    // 处理权限请求结果
    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode == 1001 && grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            CoroutineScope(Dispatchers.Main).launch {
                getCurrentLocationAndAddress()
            }
        }
    }
}

关键优势

  • getCurrentLocation()会主动请求设备的实时位置,不依赖缓存,解决了lastLocation返回null或过时数据的问题
  • 可设置超时时间,避免无限等待定位结果
  • 通过setMaxUpdateAgeMillis(0)强制获取新鲜位置数据,确保准确性
  • 结合Kotlin协程,代码逻辑更清晰,避免回调嵌套

注意事项

  • 如果设备处于飞行模式或无定位信号,getCurrentLocation()会抛出异常或返回null,务必做好错误处理
  • 高优先级定位会消耗更多电量,若不需要高精度,可把优先级改为PRIORITY_BALANCED_POWER_ACCURACY
  • Android 12+中,前台定位需要显示通知,可在CurrentLocationRequest中通过setForegroundServiceType()配置

内容的提问来源于stack exchange,提问作者Cipri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 18:01:28