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

如何在设备移动时覆盖Doze模式?后台定位轮询技术需求咨询

嘿,你已经搞定了充电时持续轮询的需求,现在要解决设备静止时停止定位轮询的问题对吧?我给你梳理几个可行的方案,都是基于你目前用的Firebase JobDispatcher来实现的:

解决方案:设备静止时停止Firebase JobDispatcher的定位轮询

一、先搞定设备静止状态的检测

判断设备是否静止有两种靠谱的方式,你可以根据需求选:

1. 基于位置位移判断

利用Fused Location Provider获取最近的位置记录,计算相邻位置的距离,如果在一段时间内(比如5分钟)位移小于某个阈值(比如10米),就判定为设备静止。

// 示例:判断设备是否静止的工具方法
fun isDeviceStill(lastLocation: Location?, currentLocation: Location?): Boolean {
    if (lastLocation == null || currentLocation == null) return false
    // 计算两个位置的直线距离(米)
    val distance = lastLocation.distanceTo(currentLocation)
    // 位移小于10米,且时间间隔超过5分钟,判定为静止
    val timeDiff = currentLocation.time - lastLocation.time
    return distance < 10 && timeDiff > 5 * 60 * 1000
}

2. 利用Activity Recognition API(更省心)

Google的Activity Recognition API可以直接返回设备的活动状态(静止、行走、驾车等),这种方式准确率更高,还更省电。
首先请求活动状态更新:

private fun requestActivityUpdates(context: Context) {
    val task = ActivityRecognition.getClient(context)
        .requestActivityUpdates(
            60 * 1000, // 每分钟更新一次状态
            PendingIntent.getBroadcast(
                context,
                0,
                Intent(context, ActivityRecognitionReceiver::class.java),
                PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
            )
        )
    task.addOnSuccessListener { /* 订阅成功,后续会收到状态回调 */ }
}

然后写个BroadcastReceiver接收状态,把是否静止的标记存在SharedPreferences里:

class ActivityRecognitionReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        intent?.let {
            val activities = ActivityRecognitionResult.extractResult(it)
            val mostProbableActivity = activities.mostProbableActivity
            // 置信度超过70%且状态为静止时,标记设备静止
            val isStill = mostProbableActivity.type == DetectedActivity.STILL 
                    && mostProbableActivity.confidence >= 70
            
            // 保存标记到SharedPreferences,供JobService使用
            context?.getSharedPreferences("AppPrefs", Context.MODE_PRIVATE)?.edit()
                ?.putBoolean("is_device_still", isStill)?.apply()
        }
    }
}

二、在JobService中加入静止判断逻辑

每次Job触发时,先检查设备是否静止,如果是就直接结束任务,不执行定位:

class LocationPollJobService : JobService() {
    override fun onStartJob(job: JobParameters?): Boolean {
        // 从SharedPreferences读取当前设备是否静止的标记
        val isStill = getSharedPreferences("AppPrefs", MODE_PRIVATE)
            .getBoolean("is_device_still", false)
        
        if (isStill) {
            // 设备静止,直接结束Job,不执行定位
            jobFinished(job, false)
            return false
        }
        
        // 设备非静止,执行你的定位轮询逻辑
        performLocationPoll()
        
        // 如果定位是异步操作,返回true,完成后记得调用jobFinished
        return true
    }

    override fun onStopJob(job: JobParameters?): Boolean {
        // 可选:取消正在进行的定位操作
        return true // 返回true表示需要重新调度Job
    }

    private fun performLocationPoll() {
        // 这里写你的定位逻辑代码
    }
}

三、进阶优化:动态启停Job(更省电)

如果想进一步节省电量,可以在检测到设备静止时直接取消Job调度,当设备恢复移动时再重新调度:

// 取消已调度的后台Job
fun cancelBackgroundJob(context: Context) {
    val dispatcher = FirebaseJobDispatcher(GooglePlayDriver(context))
    dispatcher.cancel(backgroundJobKey)
}

// 重新调度后台Job(和你原来的调度逻辑一致)
fun scheduleBackgroundJob(context: Context) {
    val dispatcher = FirebaseJobDispatcher(GooglePlayDriver(context))
    val job = dispatcher.newJobBuilder()
        .setService(LocationPollJobService::class.java)
        .setTag(backgroundJobKey)
        .setRecurring(true)
        .setTrigger(Trigger.executionWindow(60, 60)) // 1分钟轮询周期
        .setLifetime(Lifetime.FOREVER)
        .setConstraints(Constraint.DEVICE_CHARGING) // 保留充电时执行的约束
        .setReplaceCurrent(true)
        .build()
    dispatcher.schedule(job)
}

然后修改ActivityRecognitionReceiver,根据状态切换Job的启停:

override fun onReceive(context: Context?, intent: Intent?) {
    // ... 前面的代码获取isStill ...
    val prefs = context?.getSharedPreferences("AppPrefs", Context.MODE_PRIVATE)
    val wasStill = prefs?.getBoolean("is_device_still", false) ?: false
    
    if (isStill && !wasStill) {
        // 设备从移动变为静止,取消Job调度
        cancelBackgroundJob(context!!)
    } else if (!isStill && wasStill) {
        // 设备从静止变为移动,重新调度Job
        scheduleBackgroundJob(context!!)
    }
    
    // 更新SharedPreferences里的静止标记
    prefs?.edit()?.putBoolean("is_device_still", isStill)?.apply()
}

注意事项

  • 别忘了在AndroidManifest.xml中注册LocationPollJobService和ActivityRecognitionReceiver,还要添加必要的权限:ACCESS_FINE_LOCATION、ACTIVITY_RECOGNITION(Android 12+需要运行时请求这个权限)。
  • Activity Recognition的更新间隔别设太频繁,1-5分钟一次就足够,避免不必要的电量消耗。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 04:00:44