Android无网络环境下后台持续获取经纬度更新异常问题
Android后台位置追踪无网络/无离线地图时停止更新的问题
我开发了一款Android位置追踪应用,要求后台每分钟保存用户坐标。在装有谷歌离线地图的设备上运行正常,但在既无离线地图也无网络的设备上,运行一段时间后会停止接收位置更新。我尝试了Google Fused API和基于GPS_Provider的LocationManager两种方案,都出现了相同问题。
以下是我的代码:
public class BackgroundLocationService extends Service { @Override public void onCreate() { super.onCreate(); initData(); } //Location Callback private LocationCallback locationCallback = new LocationCallback() { @Override public void onLocationResult(LocationResult locationResult) { super.onLocationResult(locationResult); Location currentLocation = locationResult.getLastLocation(); lat= Double.toString(currentLocation.getLatitude()); longit=Double.toString(currentLocation.getLongitude()); } }; @Override public int onStartCommand(Intent intent, int flags, int startId) { prepareForegroundNotification(""); startLocationUpdates(); return START_STICKY; } @SuppressLint("MissingPermission") private void startLocationUpdates() { mFusedLocationClient.requestLocationUpdates(this.locationRequest, this.locationCallback, Looper.myLooper()); } private void prepareForegroundNotification(String msg) { if(msg.length()==0) { msg="HCM Location Tracking"; } else { msg="HCM, "+msg; } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel serviceChannel = new NotificationChannel( "1", msg, NotificationManager.IMPORTANCE_HIGH ); NotificationManager manager = getSystemService(NotificationManager.class); manager.createNotificationChannel(serviceChannel); } Intent notificationIntent = new Intent(this, SplashActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(this, 121, notificationIntent, PendingIntent.FLAG_IMMUTABLE); Notification notification = new NotificationCompat.Builder(this, "1") .setContentTitle(getString(R.string.app_name)) .setContentTitle(msg) .setSmallIcon(R.mipmap.ic_launcher) .setContentIntent(pendingIntent) .build(); startForeground(1, notification); } @Nullable @Override public IBinder onBind(Intent intent) { return null; } private void initData() { locationRequest = new LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, UPDATE_INTERVAL_IN_MILLISECONDS) .setWaitForAccurateLocation(false) .setMinUpdateIntervalMillis(UPDATE_INTERVAL_IN_MILLISECONDS) .setMaxUpdateDelayMillis(UPDATE_INTERVAL_IN_MILLISECONDS) .build(); mFusedLocationClient = LocationServices.getFusedLocationProviderClient(Global.getInstance()); gpsTracker = new GPSTracker( this); getCoordinatesFromMangerHandler(); locationSettings(); } private void getCoordinatesFromMangerHandler() { mHandler.postDelayed(new Runnable() { @Override public void run() { getCoordinatesFromManger(); mHandler.postDelayed(this, CHECK_INTERVAL); } }, CHECK_INTERVAL); } private void getCoordinatesFromManger() { if(gpsTracker==null){ gpsTracker = new GPSTracker( this); } gpsTracker.getLocation(); lat= Double.toString(gpsTracker.getLatitude()); longit=Double.toString(gpsTracker.getLongitude()); } private void locationSettings() { LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder() .addLocationRequest(locationRequest); SettingsClient client = LocationServices.getSettingsClient(this); Task<LocationSettingsResponse> task = client.checkLocationSettings(builder.build()); task.addOnSuccessListener(new OnSuccessListener<LocationSettingsResponse>() { @Override public void onSuccess(LocationSettingsResponse locationSettingsResponse) { } }); task.addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { if (e instanceof ResolvableApiException) { try { ResolvableApiException resolvable = (ResolvableApiException) e; prepareForegroundNotification("Kindly enable Wi-Fi scanning and location."); } catch (Exception sendEx) { } } } }); } @Override public void onDestroy() { super.onDestroy(); Intent broadcastIntent = new Intent(); broadcastIntent.setAction("restartservice"); broadcastIntent.setClass(this, RestartUserActivity.class); this.sendBroadcast(broadcastIntent); } }
问题原因分析
- GPS信号与节电策略:无网络时,设备可能触发节电模式关闭GPS模块;或GPS长时间无法锁定卫星后,系统自动停止扫描以节省电量。
- Fused API的网络依赖:即使设置了
PRIORITY_HIGH_ACCURACY,Fused Location Provider仍依赖网络基站/Wi-Fi热点辅助定位,无网络时可能降低定位频率甚至停止更新。 - Service稳定性不足:
START_STICKY无法保证服务不被系统回收,广播重启机制在部分系统版本或厂商定制ROM中可能失效。 - 重复定位逻辑冲突:代码同时运行Fused API回调和Handler定时调用GPS Tracker,两种逻辑抢占定位资源,导致系统限制定位服务。
修复方案
1. 优化定位请求配置
调整LocationRequest参数,确保无网络时GPS持续工作:
locationRequest = new LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, 60000) // 1分钟更新间隔 .setWaitForAccurateLocation(false) .setMinUpdateIntervalMillis(50000) // 最小间隔设为50秒,避免频繁请求 .setMaxUpdateDelayMillis(65000) .build();
如果需要强制仅使用GPS,可通过LocationSettingsRequest配置强制开启GPS优先模式。
2. 处理GPS定位超时与重试
在GPSTracker类中添加超时重试逻辑,避免GPS长时间无响应后停止工作:
// GPSTracker类中新增方法 public void restartGPS() { if (locationManager != null) { locationManager.removeUpdates(locationListener); // 重新注册GPS监听 locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 60000, 0, locationListener, Looper.getMainLooper()); } }
3. 强化后台存活能力
- 优化前台服务:将通知优先级设为
IMPORTANCE_DEFAULT或IMPORTANCE_LOW,避免被系统判定为高耗电应用;同时确保通知持续可见,维持前台状态。 - 申请电池优化豁免:引导用户将应用加入电池优化白名单,Android 6.0+可通过
ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS发起请求。 - 替换重启机制:用
WorkManager或JobScheduler替代广播重启,这两种组件更适配Android后台调度规则,能更可靠地重启定位任务。
4. 移除重复定位逻辑
选择Fused API或LocationManager其中一种方案,避免资源冲突:
- 保留Fused API则删除
getCoordinatesFromMangerHandler及相关GPS Tracker代码。 - 保留LocationManager则监听GPS状态广播,在GPS启用/禁用时及时调整定位逻辑。
5. 添加GPS状态监控
注册广播接收器监听GPS状态变化,及时处理GPS关闭/开启事件:
private BroadcastReceiver gpsStatusReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (LocationManager.PROVIDER_DISABLED_ACTION.equals(action)) { prepareForegroundNotification("GPS已关闭,请重新开启"); } else if (LocationManager.PROVIDER_ENABLED_ACTION.equals(action)) { startLocationUpdates(); } } }; // 在onCreate中注册接收器 @Override public void onCreate() { super.onCreate(); initData(); IntentFilter filter = new IntentFilter(); filter.addAction(LocationManager.PROVIDER_ENABLED_ACTION); filter.addAction(LocationManager.PROVIDER_DISABLED_ACTION); registerReceiver(gpsStatusReceiver, filter); } // 在onDestroy中注销接收器 @Override public void onDestroy() { super.onDestroy(); unregisterReceiver(gpsStatusReceiver); // 原有销毁逻辑... }
内容的提问来源于stack exchange,提问作者Umair Ahmed
相关产品推荐
相关产品推荐

