【问题标题】:Run Service to collect sensor data only when user is moving仅在用户移动时运行服务以收集传感器数据
【发布时间】:2021-10-04 14:24:00
【问题描述】:

我想在用户移动/手机不静止时跟踪传感器数据(加速度计、陀螺仪)。

我能做的事情:

  1. 使用传感器监听器监听传感器数据
        sensorManager = getSystemService(SENSOR_SERVICE) as SensorManager
        
        val accelerometerSensor = 
        sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
    
        sensorManager.registerListener(
                accSensor,
                accelerometerSensor,
                SensorManager.SENSOR_DELAY_NORMAL
            )
  1. 运行始终在后台持续运行的前台服务,以跟踪传感器,即使该应用已从最近的应用中删除也是如此
serviceIntent = Intent(context, SensorService::class.java)
context.startForegroundService(serviceIntent)
  1. 在应用重新启动后立即使用广播侦听器启动服务,该侦听器侦听启动完成事件。

但我无法:

  1. 停止在设备停止移动时收集传感器数据的传感器服务。
  2. 当用户的设备开始移动并收集传感器数据时启动传感器(未运行)。

从系统接收运动开始和运动结束通知/回调的方式可能是什么,以便我们可以决定启动/结束前台服务。

【问题讨论】:

  • 您的问题能否改写为“手机移动时是否会触发任何系统通知?”或者您的问题更像是“移动手机时会触发系统通知,但我所有尝试收听它的尝试都失败了”
  • 但主要问题是“为什么?” meta.stackexchange.com/questions/66377/what-is-the-xy-problem 为什么需要这个?例如 - 为了节省电池......那么你可能走错了路。
  • @x00 我喜欢相信第一个,但如果我没有正确执行它也可能是第二个。
  • 你有什么建议可以节省电池而不是一直显示通知(这会惹恼用户)。但是这两种情况都有几乎相同的解决方案。现在我的好奇心是,您认为只有在用户移动时才能记录传感器(加速度计和磁力计)的更好方法是什么。

标签: java android kotlin android-service android-sensors


【解决方案1】:

评论太大了,所以我会发布它作为答案。这在某种程度上是一个答案,但没有证据,只是我的经验。

我绝不是 Android 方面的专家。但我一般对传感器了解一两件事。最主要的是它们始终处于活动状态(如果没有完全关闭),并且总是有一些噪音。所以

  1. 不能 100% 确定是否有任何运动。相反,您需要收集所有事件,选择您的阈值自己决定。 (可能您希望汇总来自多个传感器的测量值来做出决定,甚至考虑测量历史 - 例如,如果用户在崎岖不平的道路上开车,噪音会在很长一段时间内更高)。
  2. 如果相应的代码将由操作系统或您的服务执行,则能耗几乎没有差异。但是有更多的机会可以使用您的代码自定义阈值、聚合和其他逻辑。这就是为什么我认为 OS 将 API 保持在最低限度,并且没有像 moving starts/moving stops 这样的事件。
  3. 唯一消耗超过最小值的能量是您的代码。没有其他人,但您的代码决定是否通过不断的通知流来惹恼用户。

因此,请考虑聚合策略和阈值,如果未通过阈值,则不要显示通知,并使您的代码快速(这样就不会消耗太多能量)。你已经完成了......或多或少......因为这些决定并不容易做出。大公司的许多应用程序在所有情况下都无法使它们正确。只需安装几个计步器应用程序,您就会发现它们都会显示不同的步数。

【讨论】:

  • 你知道如何一直监听传感器来决定是否显示通知吗?因为据我所知,为了能够一直收听传感器,除了显示一致的通知之外别无他法
  • 正如我所说:'我绝不是 Android 专家。但是……'但是你说的很奇怪。传感器和通知不能是同一个 API。没门!所以我查看了来自@user3252344 的链接,并在谷歌上搜索了一下(例如这里是developer.android.com/guide/topics/sensors/sensors_overview,这里是code.tutsplus.com/tutorials/…),我什么也没看到关于强制通知。也许您正在使用其他一些 API - 不适合您的任务。
  • Android 在需要资源时会在后台杀死服务,以避免我们需要运行需要通知的前台服务,否则,当我们从最近的应用程序中滑动时,该服务也会被杀死,我们赢了'无法接收传感器更新。
  • 这就是我在第一条评论中所说的:你问错了问题。再做一个,关于你的问题的根源:“如何让服务保持活力?”
【解决方案2】:

什么是“移动”的阈值取决于您的应用程序,因此没有很多现成的选项(例如,您是否关心用户是否摇晃手机,或者是否关心他们是否在车内某处移动了几条街道?)。

有一些传感器类型可以检测运动开始/停止。见here。它们是否适合您的应用取决于您的应用。

  1. 停止传感器:

TYPE_STATIONARY_DETECT 在用户 5 秒内未移动时触发事件。听它,并用它来停止你的服务。如果你想比这更快,你必须自己做。

  1. 启动传感器

TYPE_MOVEMENT_DETECT 与静止检测相反,当用户移动 5 秒时触发。如果 5 秒的延迟不影响交易,您可以收听此消息以启动服务备份。

如果您希望您的动作将应用从睡眠状态中唤醒,SIGNIFICANT_MOTION 类型也可以使用,但我从来没有很幸运地找到该传感器类型的“重要”因素。

如果您的动作不是这两件事之一 - 5 秒的持续动作或任何引发“重要”标志的动作 - 那么您将需要自己实现开始和停止,因为 传感器如果尚未开始并检测到运动,则无法检测到要开始的运动。例如,我使用过类似这样的伪代码

class MotionSensorMediator:
    
    enum state=[waiting, active]

    def ctor():
        state = waiting

    def onSensorEvent(SensorEvent event):
        switch state:
             case waiting:
                  checkMovementThreshold(event)
                  break
             case active:
                  checkMovementThreshold(event)
                  sendToListener(event)
                  break

    def checkMovementThreshold(SensorEvent event):
        results = //some distance calculations
        if result > threshold && state == waiting:
             state = active
        else if result < threshold && state == active:
             state = waiting

【讨论】:

  • 我似乎无法记录在 TYPE_MOTION_DETECT 或 TYPE_STATIONARY_DETECT 的 onSensorChanged 上触发的任何事件。我想念的任何东西..没有任何提示,所以我可能错过了一些东西..
  • 任何处理这些传感器的示例应用程序/演示?
  • 这两个我个人没用过,因为不适合我的应用,所以不知道抱歉!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-12
  • 2018-06-15
  • 1970-01-01
  • 2011-11-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多