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

Android 12中GPS_PROVIDER获取车辆速度失效问题求助

Android 12(三星M21)通过GPS_PROVIDER获取车辆速度问题解决

用户问题

在三星M21(搭载Android 12系统)中,尝试通过GPS_PROVIDER的location.getSpeed()方法获取车辆速度,但无法正常工作,且onLocationChanged方法未被触发。

具体疑问:

  1. Android 12设备中能否通过GPS_PROVIDER追踪速度?
  2. 若可行,请说明使用GPS_PROVIDER获取车辆速度的正确流程。

原问题代码:

private class SpeedTask extends AsyncTask<String, Void, String> {

        final GpsMainActivity activity;
        float speed = 0.0f;
        double lat;
        LocationManager locationManager;

        public SpeedTask(GpsMainActivity activity) {
            this.activity = activity;
        }

        @Override
        protected String doInBackground(String... params) {
            locationManager = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE);
            return null;

        }

        protected void onPostExecute(String result) {
            tvUnit.setText("abc " + unit[unitType - 1]);
            LocationListener listener = new LocationListener() {
                float filtSpeed;
                float localspeed;

                @Override //not entered to this method
                public void onLocationChanged(Location location) {
                    speed = location.getSpeed();
                    System.out.println("SpeedHere:: "+speed); 
                    float multiplier = 3.6f;

                    switch (unitType) {
                        case 1:
                            multiplier = 3.6f;
                            break;
                        case 2:
                            multiplier = 2.25f;
                            break;
                        case 3:
                            multiplier = 1.0f;
                            break;

                        case 4:
                            multiplier = 1.943856f;
                            break;

                    }

                    if (maxSpeed < speed) {
                        maxSpeed = speed;
                    }


                    localspeed = speed * multiplier;
                    filtSpeed = filter(filtSpeed, localspeed, 2);
                    
                    NumberFormat numberFormat = NumberFormat.getNumberInstance();
                    numberFormat.setMaximumFractionDigits(0);


                    lat = location.getLatitude();
                    //speed=(float) location.getLatitude();
                    System.out.println("here_enter1");
                    Log.d("net.mypapit.speedview", "Speed " + localspeed + "latitude: " + lat + " longitude: " + location.getLongitude());
                    tvSpeed.setText("tvSpeed " + numberFormat.format(filtSpeed));

                    tvMaxSpeed.setText("hello " + numberFormat.format(maxSpeed * multiplier));

                    if (location.hasAltitude()) {
                        tvAccuracy.setText("stu " + numberFormat.format(location.getAccuracy()) + " m");
                    } else {
                        tvAccuracy.setText("hi NIL");
                    }

                    numberFormat.setMaximumFractionDigits(0);


                    if (location.hasBearing()) {

                        double bearing = location.getBearing();
                        String strBearing = "NIL";
                        if (bearing < 20.0) {
                            strBearing = "North";
                        } else if (bearing < 65.0) {
                            strBearing = "North-East";
                        } else if (bearing < 110.0) {
                            strBearing = "East";
                        } else if (bearing < 155.0) {
                            strBearing = "South-East";
                        } else if (bearing < 200.0) {
                            strBearing = "South";
                        } else if (bearing < 250.0) {
                            strBearing = "South-West";
                        } else if (bearing < 290.0) {
                            strBearing = "West";
                        } else if (bearing < 345.0) {
                            strBearing = "North-West";
                        } else if (bearing < 361.0) {
                            strBearing = "North";
                        }

                        tvHeading.setText(strBearing);
                    } else {
                        tvHeading.setText("NIL");
                    }

                    NumberFormat nf = NumberFormat.getInstance();

                    nf.setMaximumFractionDigits(4);


                    tvLat.setText(nf.format(location.getLatitude()));
                    tvLon.setText(nf.format(location.getLongitude()));


                }

                @Override
                public void onStatusChanged(String provider, int status, Bundle extras) {
                
                }

                @Override
                public void onProviderEnabled(String provider) {
                

                }

                @Override
                public void onProviderDisabled(String provider) {
                   


                }

            };


            if (ActivityCompat.checkSelfPermission(GpsMainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(GpsMainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                return;
            }
            locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, listener);

        }
        
        private float filter(final float prev, final float curr, final int ratio) {
            // If first time through, initialise digital filter with current values
            if (Float.isNaN(prev))
                return curr;
            // If current value is invalid, return previous filtered value
            if (Float.isNaN(curr))
                return prev;
            // Calculate new filtered value
            return (float) (curr / ratio + prev * (1.0 - 1.0 / ratio));
        }
    }

问题解答

1. Android 12能否通过GPS_PROVIDER追踪速度?

可以。GPS_PROVIDER在Android 12中仍然可用,不过系统对位置权限和定位行为的限制更严格,需要遵循新的权限规则才能正常触发位置回调。

2. 使用GPS_PROVIDER获取车辆速度的正确流程

步骤1:配置清单权限

在AndroidManifest.xml中添加必要权限和特性声明:

<!-- 精确定位权限(GPS必须) -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- 若需要后台定位,添加此权限(Android 10+) -->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<!-- 声明设备需要GPS硬件 -->
<uses-feature android:name="android.hardware.location.gps" android:required="true" />

步骤2:请求运行时权限

在Activity/Fragment中请求ACCESS_FINE_LOCATION权限,若需后台定位,需先请求前台权限再申请后台权限:

private static final int REQUEST_LOCATION_PERMISSION = 1001;

private void requestLocationPermissions() {
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
            != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                REQUEST_LOCATION_PERMISSION);
    } else {
        // 权限已获取,初始化GPS定位
        initGpsTracking();
    }
}

// 处理权限请求结果
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == REQUEST_LOCATION_PERMISSION) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            initGpsTracking();
        } else {
            // 权限被拒绝,提示用户开启
            Toast.makeText(this, "需要定位权限才能获取速度", Toast.LENGTH_SHORT).show();
        }
    }
}

步骤3:检查GPS是否启用

在初始化定位前,检查GPS是否开启,若未开启引导用户到设置页面:

private void checkGpsStatus() {
    LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    boolean isGpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
    if (!isGpsEnabled) {
        // 引导用户开启GPS
        Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
        startActivity(intent);
    }
}

步骤4:正确注册/移除LocationListener

在Activity的生命周期方法中注册和移除监听,避免内存泄漏和无效定位:

private LocationManager locationManager;
private LocationListener gpsListener;

private void initGpsTracking() {
    locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    checkGpsStatus();

    gpsListener = new LocationListener() {
        @Override
        public void onLocationChanged(@NonNull Location location) {
            // 处理速度数据
            float speed = location.getSpeed(); // 单位:m/s
            // 转换为km/h:speed * 3.6
            updateSpeedUI(speed);
        }

        @Override
        public void onProviderEnabled(@NonNull String provider) {
            Toast.makeText(GpsMainActivity.this, "GPS已启用", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onProviderDisabled(@NonNull String provider) {
            Toast.makeText(GpsMainActivity.this, "GPS已关闭,请开启", Toast.LENGTH_SHORT).show();
            checkGpsStatus();
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {}
    };

    // 注册位置更新:设置合理的时间间隔和距离阈值
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
            == PackageManager.PERMISSION_GRANTED) {
        // 每1秒更新一次,距离变化0米时更新
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
                1000, 0, gpsListener);
    }
}

// 在Activity停止时移除监听
@Override
protected void onStop() {
    super.onStop();
    if (locationManager != null && gpsListener != null) {
        locationManager.removeUpdates(gpsListener);
    }
}

// 更新UI的方法
private void updateSpeedUI(float speed) {
    float multiplier = 3.6f; // 默认km/h
    switch (unitType) {
        case 1:
            multiplier = 3.6f;
            break;
        case 2:
            multiplier = 2.25f; // 转换为mph
            break;
        case 3:
            multiplier = 1.0f; // 保持m/s
            break;
        case 4:
            multiplier = 1.943856f; // 转换为节
            break;
    }
    float displaySpeed = speed * multiplier;
    // 后续UI更新逻辑和原代码一致
    tvSpeed.setText(NumberFormat.getNumberInstance().format(displaySpeed));
    // ... 其他UI更新代码
}

步骤5:注意事项

  • 避免使用AsyncTask:AsyncTask在Android 12已被废弃,且获取LocationManager无需异步操作,直接在主线程处理即可。
  • 合理设置更新参数:requestLocationUpdates的时间间隔和距离阈值不要设为0,0,系统会因省电策略限制更新频率,建议设为1000ms和0米。
  • 处理权限变更:若用户在应用运行中撤销权限,需在代码中处理,避免崩溃。

原代码问题分析

  1. AsyncTask无意义:获取LocationManager不需要异步操作,反而可能导致生命周期同步问题,使得LocationListener无法正常注册。
  2. 未检查GPS状态:如果GPS未开启,GPS_PROVIDER不会推送任何位置更新,自然不会触发onLocationChanged。
  3. 更新参数不合理:0,0的时间和距离阈值会触发系统的省电限制,导致位置更新被抑制。
  4. 生命周期管理缺失:LocationListener在AsyncTask的onPostExecute中创建,未在Activity停止时移除,容易引发内存泄漏,且Activity销毁后监听会失效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 03:50:26