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

如何让服务仅在手机待机/后台启动,移动时触发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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 08:02:02