Android 12中GPS_PROVIDER获取车辆速度失效问题求助
Android 12(三星M21)通过GPS_PROVIDER获取车辆速度问题解决
用户问题
在三星M21(搭载Android 12系统)中,尝试通过GPS_PROVIDER的location.getSpeed()方法获取车辆速度,但无法正常工作,且onLocationChanged方法未被触发。
具体疑问:
- Android 12设备中能否通过
GPS_PROVIDER追踪速度? - 若可行,请说明使用
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米。 - 处理权限变更:若用户在应用运行中撤销权限,需在代码中处理,避免崩溃。
原代码问题分析
- AsyncTask无意义:获取
LocationManager不需要异步操作,反而可能导致生命周期同步问题,使得LocationListener无法正常注册。 - 未检查GPS状态:如果GPS未开启,
GPS_PROVIDER不会推送任何位置更新,自然不会触发onLocationChanged。 - 更新参数不合理:
0,0的时间和距离阈值会触发系统的省电限制,导致位置更新被抑制。 - 生命周期管理缺失:
LocationListener在AsyncTask的onPostExecute中创建,未在Activity停止时移除,容易引发内存泄漏,且Activity销毁后监听会失效。
内容的提问来源于stack exchange,提问作者Jass Tech
相关产品推荐
相关产品推荐

