You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何计算两个地点间的距离?固定地点与用户位置测距咨询

计算固定地点与用户当前位置距离的实现优化建议

嘿,我看了你这段用来计算距离的CalDist AsyncTask代码,能感觉到你想实现固定地点到用户当前位置的距离测算,但目前代码还不完整,而且有个关键问题得注意——AsyncTask在Android API 30及以上已经被官方废弃啦!我给你整理一套更现代、完整的实现方案,不管是算直线距离还是实际导航距离都能用~


核心实现思路

我们可以用Kotlin协程替代过时的AsyncTask,同时提供两种实用的距离计算方式:

  • 直线距离(用Haversine公式,无需调用第三方API)
  • 实际导航距离(调用Google Maps Directions API,支持步行/驾车/骑行)

1. 先完成权限准备

首先要在AndroidManifest.xml中添加位置权限,确保能获取用户当前位置:

<!-- 粗略位置权限 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- 精确定位权限 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- 后台定位权限(如果需要后台持续获取位置) -->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" android:maxSdkVersion="32" />

2. 获取用户当前位置

用Google推荐的FusedLocationProviderClient来获取当前位置,比自己管理位置监听更稳定:

private fun getCurrentLocation(): Task<Location> {
    val fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
    return fusedLocationClient.lastLocation
}

3. 计算直线距离(无需API)

如果只需要两点间的直线距离,直接用Haversine公式计算就行,不用调用外部接口:

// 计算两个坐标间的直线距离,单位:米
fun calculateStraightDistance(lat1: Double, lon1: Double, lat2: Double, lon2: Double): Double {
    val earthRadius = 6371000.0 // 地球半径,单位米
    val dLat = Math.toRadians(lat2 - lat1)
    val dLon = Math.toRadians(lon2 - lon1)
    val a = Math.sin(dLat/2) * Math.sin(dLat/2) +
            Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
            Math.sin(dLon/2) * Math.sin(dLon/2)
    val c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a))
    return earthRadius * c
}

4. 获取实际导航距离(调用API)

如果需要道路导航的实际距离,就调用Google Maps Directions API,用协程处理网络请求避免阻塞主线程:

// 替换成你在Google Cloud Console申请的API Key
private const val GOOGLE_MAPS_API_KEY = "YOUR_API_KEY_HERE"

suspend fun getNavigationDistance(originLat: Double, originLon: Double, destLat: Double, destLon: Double): String? {
    val requestUrl = "https://maps.googleapis.com/maps/api/directions/json?" +
            "origin=$originLat,$originLon" +
            "&destination=$destLat,$destLon" +
            "&mode=driving" // 可选模式:walking/bicycling/transit
            "&key=$GOOGLE_MAPS_API_KEY"

    return try {
        val response = OkHttpClient().newCall(Request.Builder().url(requestUrl).build()).await()
        if (response.isSuccessful) {
            val jsonResponse = response.body?.string() ?: return "数据解析失败"
            val jsonObject = JSONObject(jsonResponse)
            val routes = jsonObject.getJSONArray("routes")
            if (routes.length() > 0) {
                val legs = routes.getJSONObject(0).getJSONArray("legs")
                legs.getJSONObject(0).getJSONObject("distance").getString("text")
            } else {
                "无可用路线"
            }
        } else {
            "请求失败"
        }
    } catch (e: Exception) {
        e.printStackTrace()
        "计算出错"
    }
}

5. 完整调用流程(协程版)

在Activity中用协程启动整个流程,同时处理权限检查和UI更新:

lifecycleScope.launch {
    // 先检查位置权限
    if (ContextCompat.checkSelfPermission(this@YourActivity, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this@YourActivity, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 100)
        return@launch
    }

    // 获取当前位置
    val currentLocation = getCurrentLocation().await()
    currentLocation?.let {
        // 替换成你的固定地点坐标(示例:北京天安门)
        val fixedLat = 39.9042
        val fixedLon = 116.4074

        // 计算直线距离并格式化
        val straightDistance = calculateStraightDistance(it.latitude, it.longitude, fixedLat, fixedLon)
        val straightDistanceText = String.format("%.2f米", straightDistance)

        // 获取导航距离
        val navigationDistanceText = getNavigationDistance(it.latitude, it.longitude, fixedLat, fixedLon)

        // 更新UI(回到主线程操作)
        runOnUiThread {
            tvStraightDistance.text = "直线距离:$straightDistanceText"
            tvNavDistance.text = "驾车距离:${navigationDistanceText ?: "获取失败"}"
        }
    } ?: run {
        runOnUiThread {
            Toast.makeText(this@YourActivity, "无法获取当前位置", Toast.LENGTH_SHORT).show()
        }
    }
}

额外注意事项

  • 记得在Google Cloud Console中启用Directions API,并申请有效的API Key
  • 协程需要添加依赖:implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"
  • OkHttp依赖:implementation "com.squareup.okhttp3:okhttp:4.10.0"

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

火山引擎 最新活动