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

如何用Kotlin编写Android函数:经纬度转手机指向目标的方位角

实现步骤与代码

要实现手机指向目标位置的方位角计算,核心需要三个数据:手机当前位置、目标位置(传入的经纬度)、手机当前朝向(真北方位角),最终通过「目标相对于当前位置的初始方位角」与「手机当前朝向」的差值,得到0-359范围的结果。

1. 权限配置

在AndroidManifest.xml中添加必要权限:

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

2. 修正函数参数类型

原函数中经纬度使用Long类型是错误的,经纬度为带小数的数值,必须改为Double类型。

3. 计算两点间的初始方位角

实现工具函数,通过经纬度计算从当前位置到目标位置的初始方位角(以真北为0度,顺时针递增):

fun calculateInitialBearing(currentLat: Double, currentLng: Double, targetLat: Double, targetLng: Double): Double {
    val φ1 = Math.toRadians(currentLat)
    val φ2 = Math.toRadians(targetLat)
    val Δλ = Math.toRadians(targetLng - currentLng)

    val y = Math.sin(Δλ) * Math.cos(φ2)
    val x = Math.cos(φ1) * Math.sin(φ2) - Math.sin(φ1) * Math.cos(φ2) * Math.cos(Δλ)
    val θ = Math.atan2(y, x)

    // 将弧度转换为角度,并调整到0-360范围
    return (Math.toDegrees(θ) + 360) % 360
}

4. 获取手机当前位置(Fused Location Provider)

用Google Play服务的Fused Location Provider异步获取当前位置,这里用协程实现:

import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationServices
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException

class LocationHelper(private val fusedLocationClient: FusedLocationProviderClient) {
    suspend fun getCurrentLocation(): android.location.Location? = suspendCancellableCoroutine { continuation ->
        fusedLocationClient.lastLocation.addOnSuccessListener { location ->
            continuation.resume(location)
        }.addOnFailureListener { exception ->
            continuation.resumeWithException(exception)
        }
    }
}

5. 获取手机当前朝向(方位角)

通过旋转向量传感器获取手机的真北方位角,用Flow实时监听:

import android.content.Context
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow

class OrientationHelper(private val context: Context) {
    private val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
    private val rotationVectorSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR)

    fun getAzimuthFlow(): Flow<Float> = callbackFlow {
        val listener = object : SensorEventListener {
            override fun onSensorChanged(event: SensorEvent) {
                val rotationMatrix = FloatArray(9)
                SensorManager.getRotationMatrixFromVector(rotationMatrix, event.values)

                // 转换为方位角、俯仰角、滚转角
                val orientation = FloatArray(3)
                SensorManager.getOrientation(rotationMatrix, orientation)

                // 将方位角从-180~180范围转换为0~360
                val azimuth = (Math.toDegrees(orientation[0].toDouble()) + 360) % 360
                trySend(azimuth.toFloat())
            }

            override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {}
        }

        sensorManager.registerListener(listener, rotationVectorSensor, SensorManager.SENSOR_DELAY_NORMAL)

        awaitClose {
            sensorManager.unregisterListener(listener)
        }
    }
}

6. 整合实现目标函数

由于获取位置和传感器数据都是异步操作,采用协程挂起函数实现:

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.coroutines.flow.first

// 替换appContext为你的应用Context
private val appContext = /* 你的Context实例 */

suspend fun convertLatLongToBearing(targetLat: Double, targetLng: Double): Int = withContext(Dispatchers.IO) {
    val fusedLocationClient = LocationServices.getFusedLocationProviderClient(appContext)
    val locationHelper = LocationHelper(fusedLocationClient)
    val orientationHelper = OrientationHelper(appContext)

    // 获取当前位置,失败返回-1
    val currentLocation = locationHelper.getCurrentLocation() ?: return@withContext -1

    // 获取最新的手机方位角
    val currentAzimuth = orientationHelper.getAzimuthFlow().first()

    // 计算目标相对于当前位置的初始方位角
    val targetBearing = calculateInitialBearing(
        currentLocation.latitude,
        currentLocation.longitude,
        targetLat,
        targetLng
    )

    // 计算手机指向目标的最终方位角,调整到0-359范围
    val finalBearing = (targetBearing - currentAzimuth + 360) % 360
    finalBearing.toInt()
}

关键说明

  • 调用函数时需在协程作用域内执行(如lifecycleScope.launch)
  • 调用前必须确保已获取位置权限,否则无法获取当前位置
  • 返回值0代表当前手机已指向目标,数值为顺时针转动的角度

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 16:24:12