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

Android(Kotlin)地图显示当前位置标记问题:定位始终为空

问题分析与解决方案

一、currentLocation为空的原因及修复

1. 核心问题:lastLocation的局限性

fusedLocationProviderClient.lastLocation仅返回设备最近缓存的位置数据,如果模拟器从未获取过位置、缓存过期,就会返回null——这是你遇到空值的主要原因。

2. 修复方案:主动请求实时位置

替换lastLocation为requestLocationUpdates,主动触发位置获取,确保拿到实时数据:

private const val FINE_PERMISSION_CODE = 1
private lateinit var myMap: GoogleMap
private var currentLocation: Location? = null // 改为可空类型,避免初始化崩溃
private lateinit var fusedLocationProviderClient: FusedLocationProviderClient
private lateinit var locationRequest: LocationRequest
private lateinit var locationCallback: LocationCallback

class MapActivity : AppCompatActivity(), OnMapReadyCallback {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_map)

        fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this)
        initLocationRequest()
        getCurrentLocation()
    }

    private fun initLocationRequest() {
        locationRequest = LocationRequest.create().apply {
            interval = 10000 // 10秒更新一次
            fastestInterval = 5000 // 最快5秒更新
            priority = LocationRequest.PRIORITY_HIGH_ACCURACY
        }

        locationCallback = object : LocationCallback() {
            override fun onLocationResult(locationResult: LocationResult) {
                locationResult.lastLocation?.let { location ->
                    currentLocation = location
                    // 获取到位置后初始化地图
                    val mapFragment = supportFragmentManager.findFragmentById(R.id.map_fragment) as SupportMapFragment
                    mapFragment.getMapAsync(this@MapActivity)
                    // 可选:拿到位置后停止更新
                    fusedLocationProviderClient.removeLocationUpdates(this)
                } ?: run {
                    Log.d("Location", "null location")
                }
            }
        }
    }

    private fun getCurrentLocation() {
        // 先检查系统定位是否开启
        if (!isLocationEnabled()) {
            Toast.makeText(this, "请开启系统定位服务", Toast.LENGTH_SHORT).show()
            startActivity(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS))
            return
        }

        // 权限检查逻辑修正:只要缺少任一权限就请求
        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, Manifest.permission.ACCESS_COARSE_LOCATION), FINE_PERMISSION_CODE)
            return
        }
        // 主动请求位置更新
        fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper())
    }

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

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if(requestCode == FINE_PERMISSION_CODE) {
            if(grantResults.isNotEmpty() && grantResults.all { it == PackageManager.PERMISSION_GRANTED }) {
                getCurrentLocation()
            } else {
                Toast.makeText(this, "位置权限未授予,无法获取定位", Toast.LENGTH_SHORT).show()
            }
        }
    }

    override fun onMapReady(googleMap: GoogleMap) {
        myMap = googleMap
        currentLocation?.let { loc ->
            val curLoc = LatLng(loc.latitude, loc.longitude)
            Log.d("Location", "${loc.latitude}, ${loc.longitude}")
            myMap.addMarker(MarkerOptions().position(curLoc).title("My Location"))
            myMap.moveCamera(CameraUpdateFactory.newLatLngZoom(curLoc, 12f))
        } ?: run {
            Log.d("Location", "当前位置为空,无法添加标记")
        }
    }
}

3. 模拟器配套设置

  • 确保模拟器开启系统定位服务(设置 → 位置 → 开启)
  • 打开模拟器的「Extended Controls」(右上角三个点),在「Location」选项卡中设置模拟坐标(可直接选择城市或手动输入经纬度)

二、关闭定位后权限仍显示已授予的说明

这是正常机制:

  • 位置权限是APP访问位置信息的许可,一旦授予,除非用户手动在应用设置中撤销,否则会一直显示已授予
  • 系统定位开关是控制整个系统是否提供位置数据,关闭后即使APP有权限,也无法获取到位置数据
  • 代码中已添加isLocationEnabled()检查,会在定位关闭时提示用户跳转到设置开启

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 19:47:23