如何让服务仅在手机待机/后台启动,移动时触发FusedLocation定位更新
问题解决:优化后台待机时的定位服务触发逻辑
需求说明
现有FusedLocationProvider功能正常,已实现可在后台及手机待机时运行的前台服务,但当前服务会持续请求定位更新。需要修改为:
- 仅当应用处于后台或手机待机状态时启动服务
- 仅在用户移动时触发
onLocationResult(LocationResult locationResult)回调获取定位更新
现有代码
FusedLocationProvider相关方法
private void startLocationUpdates() { // Demander les mises à jour de position fusedLocationClient = LocationServices.getFusedLocationProviderClient(getApplicationContext()); if (fusedLocationClient != null) { if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return; } //Distance if (locationRequest == null) { locationRequest = new LocationRequest(); if (drivingtype == Constants.DRIVING_TYPE_BICYCLE) { locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY ); locationRequest.setSmallestDisplacement(Constants.GPS_UPDATE_PRECISION); locationRequest.setInterval(0); locationRequest.setFastestInterval(0); } else { locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY ); locationRequest.setSmallestDisplacement(Constants.GPS_UPDATE_PRECISION); locationRequest.setInterval(0); locationRequest.setFastestInterval(0); } } if (locationCallback == null) { locationCallback = new LocationCallback() { @Override public void onLocationResult(LocationResult locationResult) { Location location = locationResult.getLastLocation(); if (location != null) { // Traitement des mises à jour de localisation // La position a changé. Obtenez les coordonnées et mettez à jour la carte. sendLocationUpdateBroadcast(location.getLatitude(), location.getLongitude()); } } }; } Looper mainLooper = Looper.getMainLooper(); if (!locationUpdatesEnabled) { fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, mainLooper); locationUpdatesEnabled = true; } } }
服务类代码
@Override public int onStartCommand(Intent intent, int flags, int startId) { //Technique #2 new Thread( new Runnable() { @Override public void run() { while (true){ Log.d("TAG", "Foreground Service is running"); startLocationUpdates(); try { Thread.sleep(2000); } catch (InterruptedException e) { } } } } ).start(); final String CHANNEL_ID = "Foreground Service"; NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_ID, NotificationManager.IMPORTANCE_LOW); getSystemService(NotificationManager.class).createNotificationChannel(channel); Notification.Builder notification = new Notification.Builder(this, CHANNEL_ID) .setContentText("Foreground Service Running") .setContentTitle("This is Title"); startForeground(1001, notification.build()); return super.onStartCommand(intent, flags, startId); }
解决方案
1. 实现应用前后台状态监听
通过监听Activity生命周期判断应用状态,自动启停定位服务:
public class AppLifecycleObserver implements Application.ActivityLifecycleCallbacks { private int activityCount = 0; private boolean isAppInForeground = false; @Override public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {} @Override public void onActivityStarted(@NonNull Activity activity) { activityCount++; if (activityCount == 1) { isAppInForeground = true; // 应用切前台,停止定位服务 stopLocationService(); } } @Override public void onActivityResumed(@NonNull Activity activity) {} @Override public void onActivityPaused(@NonNull Activity activity) {} @Override public void onActivityStopped(@NonNull Activity activity) { activityCount--; if (activityCount == 0) { isAppInForeground = false; // 应用切后台,启动定位服务 startLocationService(); } } @Override public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {} @Override public void onActivityDestroyed(@NonNull Activity activity) {} public boolean isAppInForeground() { return isAppInForeground; } private void startLocationService() { Intent intent = new Intent(MyApplication.getInstance(), YourLocationService.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { MyApplication.getInstance().startForegroundService(intent); } else { MyApplication.getInstance().startService(intent); } } private void stopLocationService() { Intent intent = new Intent(MyApplication.getInstance(), YourLocationService.class); MyApplication.getInstance().stopService(intent); } }
在Application类中注册监听:
public class MyApplication extends Application { private static MyApplication instance; private AppLifecycleObserver lifecycleObserver; @Override public void onCreate() { super.onCreate(); instance = this; lifecycleObserver = new AppLifecycleObserver(); registerActivityLifecycleCallbacks(lifecycleObserver); } public static MyApplication getInstance() { return instance; } public boolean isAppInForeground() { return lifecycleObserver.isAppInForeground(); } }
2. 优化定位请求参数,确保仅移动时触发回调
调整LocationRequest参数,移除无效的0间隔,依赖最小位移触发更新:
private void startLocationUpdates() { fusedLocationClient = LocationServices.getFusedLocationProviderClient(getApplicationContext()); if (fusedLocationClient == null) { return; } if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return; } if (locationRequest == null) { locationRequest = new LocationRequest(); // 根据场景设置优先级,后台用平衡精度节省电量 locationRequest.setPriority(drivingtype == Constants.DRIVING_TYPE_BICYCLE ? LocationRequest.PRIORITY_HIGH_ACCURACY : LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY); // 只有移动超过该距离才触发更新 locationRequest.setSmallestDisplacement(Constants.GPS_UPDATE_PRECISION); // 设置兜底间隔,避免长时间无位移时的更新断层 locationRequest.setInterval(30000); // 30秒 locationRequest.setFastestInterval(10000); // 最快10秒 } if (locationCallback == null) { locationCallback = new LocationCallback() { @Override public void onLocationResult(LocationResult locationResult) { Location location = locationResult.getLastLocation(); if (location != null) { sendLocationUpdateBroadcast(location.getLatitude(), location.getLongitude()); } } }; } if (!locationUpdatesEnabled) { fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper()); locationUpdatesEnabled = true; } }
3. 修复服务中的无效循环
删除服务中重复调用startLocationUpdates()的循环,只需调用一次即可持续监听:
@Override public int onStartCommand(Intent intent, int flags, int startId) { // 创建通知渠道并启动前台服务 final String CHANNEL_ID = "Foreground Service"; NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_ID, NotificationManager.IMPORTANCE_LOW); getSystemService(NotificationManager.class).createNotificationChannel(channel); Notification notification = new Notification.Builder(this, CHANNEL_ID) .setContentText("后台定位服务运行中") .setContentTitle("定位服务") .setSmallIcon(R.drawable.ic_notification) // 需添加通知图标资源 .build(); startForeground(1001, notification); // 启动定位更新,仅需调用一次 startLocationUpdates(); return START_STICKY; // 服务被系统杀死后自动重启 }
4. 待机状态保持服务运行(可选)
若需要手机待机时持续定位,需添加唤醒锁权限并实现:
在AndroidManifest.xml中添加权限:
<uses-permission android:name="android.permission.WAKE_LOCK" />
在服务类中添加唤醒锁逻辑:
private PowerManager.WakeLock wakeLock; @Override public void onCreate() { super.onCreate(); PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE); wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "LocationService:WakeLock"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // ... 通知代码 ... // 获取唤醒锁,保持CPU运行 if (!wakeLock.isHeld()) { wakeLock.acquire(); } startLocationUpdates(); return START_STICKY; } @Override public void onDestroy() { super.onDestroy(); // 释放唤醒锁 if (wakeLock.isHeld()) { wakeLock.release(); } // 停止定位更新,避免资源泄漏 if (fusedLocationClient != null && locationCallback != null) { fusedLocationClient.removeLocationUpdates(locationCallback); locationUpdatesEnabled = false; } }
内容的提问来源于stack exchange,提问作者ΩlostA
相关产品推荐
相关产品推荐

