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

如何借助Geocoder在onSensorChanged方法中使用用户当前坐标实现指南针

解决方案

核心改动说明

  • 新增私有成员变量存储用户当前经纬度和位置有效性标记,在onLocationChanged回调中实时更新用户位置
  • 新增位置服务相关的注册/注销方法,确保可以获取系统推送的位置更新
  • 优化onSensorChanged逻辑,判断位置有效后再代入计算目标方位角,同时删除冗余的重复计算代码
  • 预留目标坐标的设置入口,方便后续灵活修改指向的目标位置

修改后完整代码

public class Compass implements SensorEventListener, LocationListener {

    private static final String TAG = "Compass";
    // 新增:存储用户当前位置
    private double userLat = 0.0;
    private double userLng = 0.0;
    // 新增:标记位置是否有效,避免无位置时计算出错
    private boolean isLocationValid = false;
    // 新增:目标坐标,可通过set方法修改
    private double targetLat = 21.422487;
    private double targetLng = 39.826206;

    protected double bearing(double startLat, double startLng, double endLat, double endLng){
        double longitude1 = startLng;
        double longitude2 = endLng;
        double latitude1 = Math.toRadians(startLat);
        double latitude2 = Math.toRadians(endLat);
        double longDiff= Math.toRadians(longitude2-longitude1);
        double y= Math.sin(longDiff)*Math.cos(latitude2);
        double x=Math.cos(latitude1)*Math.sin(latitude2)-Math.sin(latitude1)*Math.cos(latitude2)*Math.cos(longDiff);

        return (Math.toDegrees(Math.atan2(y, x))+360)%360;
    }

    Geocoder geocoder;
    List<Address> addresses;

    @Override
    public void onSensorChanged(SensorEvent event) {
        final float alpha = 0.97f;

        synchronized (this) {
            if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
                mGravity[0] = alpha * mGravity[0] + (1 - alpha) * event.values[0];
                mGravity[1] = alpha * mGravity[1] + (1 - alpha) * event.values[1];
                mGravity[2] = alpha * mGravity[2] + (1 - alpha) * event.values[2];
            }

            if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
                mGeomagnetic[0] = alpha * mGeomagnetic[0] + (1 - alpha) * event.values[0];
                mGeomagnetic[1] = alpha * mGeomagnetic[1] + (1 - alpha) * event.values[1];
                mGeomagnetic[2] = alpha * mGeomagnetic[2] + (1 - alpha) * event.values[2];
            }

            boolean success = SensorManager.getRotationMatrix(R, I, mGravity, mGeomagnetic);
            if (success) {
                float orientation[] = new float[3];
                SensorManager.getOrientation(R, orientation);
                azimuth = (float) Math.toDegrees(orientation[0]);
                azimuth = (azimuth + azimuthFix + 360) % 360;
                // 新增:只有位置有效时才计算指向目标的方位差
                if (isLocationValid) {
                    double targetBearing = bearing(userLat, userLng, targetLat, targetLng);
                    azimuth = (azimuth - (float)targetBearing + 360) % 360;
                }

                if (listener != null) {
                    listener.onNewAzimuth(azimuth);
                }
            }
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }

    @Override
    public void onLocationChanged(@NonNull Location location) {
        // 新增:更新用户位置
        userLat = location.getLatitude();
        userLng = location.getLongitude();
        isLocationValid = true;
    }

    // 新增:设置目标坐标的方法
    public void setTargetLocation(double lat, double lng) {
        this.targetLat = lat;
        this.targetLng = lng;
    }

    // 新增:注册位置监听的方法,需要外部先获取位置权限
    public void registerLocationListener(LocationManager locationManager) throws SecurityException {
        // 可以根据需求调整位置更新的最小时间和距离阈值
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 1f, this);
        // 也可以同时注册网络位置源,提高室内定位可用性
        locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000, 1f, this);
    }

    // 新增:注销位置监听的方法
    public void unregisterLocationListener(LocationManager locationManager) {
        locationManager.removeUpdates(this);
        isLocationValid = false;
    }

    public interface CompassListener {
        void onNewAzimuth(float azimuth);
    }

    private CompassListener listener;

    private SensorManager sensorManager;
    private Sensor gsensor;
    private Sensor msensor;

    private float[] mGravity = new float[3];
    private float[] mGeomagnetic = new float[3];
    private float[] R = new float[9];
    private float[] I = new float[9];

    private float azimuth;
    private float azimuth2;
    private float azimuthFix;

    public Compass(Context context) {
        sensorManager = (SensorManager) context
                .getSystemService(Context.SENSOR_SERVICE);
        gsensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        msensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
    }

    public void start() {
        sensorManager.registerListener(this, gsensor,
                SensorManager.SENSOR_DELAY_GAME);
        sensorManager.registerListener(this, msensor,
                SensorManager.SENSOR_DELAY_GAME);
    }

    public void stop() {
        sensorManager.unregisterListener(this);
    }

    public void setAzimuthFix(float fix) {
        azimuthFix = fix;
    }

    public void resetAzimuthFix() {
        setAzimuthFix(0);
    }

    public void setListener(CompassListener l) {
        listener = l;
    }
}

调用步骤

  1. 先在AndroidManifest.xml中添加所需权限:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
  1. 在Activity中先动态申请位置权限,权限通过后再执行以下逻辑:
// 初始化
Compass compass = new Compass(this);
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
// 设置回调
compass.setListener(azimuth -> {
    // 这里更新指南针UI,旋转对应角度即可
    yourCompassView.setRotation(-azimuth);
});
// 启动传感器和位置监听
compass.start();
try {
    compass.registerLocationListener(locationManager);
} catch (SecurityException e) {
    e.printStackTrace();
}
  1. 在Activity销毁时注销监听避免内存泄漏:
@Override
protected void onDestroy() {
    super.onDestroy();
    compass.stop();
    compass.unregisterLocationListener(locationManager);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 17:42:01