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

Android Studio Kotlin中LatLng类型不匹配及未解析引用问题求助

修复LocationService类中的类型不匹配与未解析引用错误

错误原因分析

  • 类型不匹配:代码混用了两个不同包的LatLng类:com.google.android.gms.maps.model.LatLng(Android地图SDK)和com.google.maps.model.LatLng(Google Maps服务Java客户端)。Places API方法需要后者,但代码传递了前者,导致类型冲突。
  • 未解析引用bounds:Google Places API的nearbySearchQuery没有.bounds()方法,正确的方法名是.locationRestriction(),用于传入矩形边界。

修复后的完整代码

import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.location.Location
import androidx.core.content.ContextCompat
import com.example.eventfinder.utils.LocationUtils
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationServices
import com.google.android.gms.maps.model.LatLng as AndroidLatLng
import com.google.maps.GeoApiContext
import com.google.maps.PlacesApi
import com.google.maps.model.LatLng as GoogleMapsLatLng
import com.google.maps.model.LatLngBounds as GoogleMapsLatLngBounds
import com.google.maps.model.PlacesSearchResult
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.tasks.await
import kotlinx.coroutines.withContext
import kotlin.math.min

class LocationService(private val context: Context) {
    private val fusedLocationClient: FusedLocationProviderClient =
        LocationServices.getFusedLocationProviderClient(context)
    private val locationPermission = Manifest.permission.ACCESS_FINE_LOCATION
    private val apiKey = "Your API Key" // Replace with your API key

    interface LocationCallback {
        fun onLocationResult(location: Location?)
        fun onCitiesAndRegionsWithinRadiusResult(cityAndRegionNames: List<String>)
        fun onError(errorMessage: String)
    }

    fun getLastLocation(callback: LocationCallback) {
        GlobalScope.launch {
            try {
                val location = retrieveLastLocation()
                withContext(Dispatchers.Main) {
                    callback.onLocationResult(location)
                }
            } catch (e: Exception) {
                withContext(Dispatchers.Main) {
                    callback.onError("Error while retrieving location: ${e.message}")
                }
            }
        }
    }

    private suspend fun retrieveLastLocation(): Location? {
        if (ContextCompat.checkSelfPermission(context, locationPermission) == PackageManager.PERMISSION_GRANTED) {
            if (LocationUtils.isLocationEnabled(context)) {
                return try {
                    fusedLocationClient.lastLocation.await()
                } catch (exception: Exception) {
                    throw Exception("Error while retrieving location: ${exception.message}")
                }
            } else {
                throw Exception("Location services are not enabled.")
            }
        }
        throw Exception("Location permission not granted.")
    }

    fun getCitiesAndRegionsWithinExtendedRadius(location: Location, extendedRadiusKm: Double, callback: LocationCallback) {
        GlobalScope.launch {
            try {
                val cityAndRegionNames = lookupCitiesAndRegions(location, extendedRadiusKm)
                withContext(Dispatchers.Main) {
                    callback.onCitiesAndRegionsWithinRadiusResult(cityAndRegionNames.distinct())
                }
            } catch (e: Exception) {
                withContext(Dispatchers.Main) {
                    callback.onError("Error while looking up cities: ${e.message}")
                }
            }
        }
    }

    private suspend fun lookupCitiesAndRegions(location: Location, extendedRadiusKm: Double): List<String> {
        val maxRadius = 50000.0 // Maximum radius in meters (50 km)
        val centerAndroid = AndroidLatLng(location.latitude, location.longitude)
        // 转换为Google Maps服务SDK的LatLng类型
        val centerGoogle = GoogleMapsLatLng(location.latitude, location.longitude)
        val geoContext = GeoApiContext.Builder().apiKey(apiKey).build()
        val cityAndRegionNames = mutableListOf<String>()

        var currentRadiusMeters = 0.0
        while (currentRadiusMeters < extendedRadiusKm * 1000) {
            val remainingRadiusMeters = min(maxRadius, (extendedRadiusKm * 1000 - currentRadiusMeters))
            val bounds = getGoogleMapsBounds(centerAndroid, remainingRadiusMeters)

            // 使用正确的locationRestriction方法设置边界
            val placesRequest = PlacesApi.nearbySearchQuery(geoContext, centerGoogle)
                .radius(remainingRadiusMeters.toInt())
                .locationRestriction(bounds)

            try {
                val placesResult = placesRequest.await()
                for (result: PlacesSearchResult in placesResult.results) {
                    for (type in result.types) {
                        if (type == "locality" || type == "administrative_area_level_1") {
                            cityAndRegionNames.add(result.name)
                            break
                        }
                    }
                }
            } catch (e: Exception) {
                throw Exception("Error while looking up cities: ${e.message}")
            }

            currentRadiusMeters += maxRadius
        }

        return cityAndRegionNames
    }

    // 生成Google Maps服务SDK所需的LatLngBounds
    private fun getGoogleMapsBounds(center: AndroidLatLng, radiusMeters: Double): GoogleMapsLatLngBounds {
        val latLngPerMeter = 1.0 / 111319.9 // 1米对应的经纬度近似值
        val latLngRadius = radiusMeters * latLngPerMeter
        val southwest = GoogleMapsLatLng(center.latitude - latLngRadius, center.longitude - latLngRadius)
        val northeast = GoogleMapsLatLng(center.latitude + latLngRadius, center.longitude + latLngRadius)
        return GoogleMapsLatLngBounds.newInstance(southwest, northeast)
    }
}

关键修复点

  1. 类别名区分:给两个不同包的LatLng/LatLngBounds设置别名,彻底避免类型混淆。
  2. 类型适配转换:将Android SDK的地理位置对象转换为Google Maps服务SDK的对应类型,满足Places API参数要求。
  3. API方法修正:把错误的.bounds()调用替换为官方文档指定的.locationRestriction()方法。
  4. 边界生成调整:修改边界计算方法,直接生成Places API所需的LatLngBounds对象。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 20:57:13