【问题标题】:get sensor data every 1/10th second每 1/10 秒获取传感器数据
【发布时间】:2017-10-19 21:35:21
【问题描述】:

我正在尝试每 1/10 秒记录一次 Android 传感器数据(加速度计、陀螺仪)。使用 Android 提供的值(AI、GAME、NORMAL)或用户定义的值(例如 100000 微秒)完全没有区别,onSensorChanged 每 1/100 秒触发一次。这对电池寿命和日志文件的大小(每天要记录 6000 万个事件)都是不利的。

我可以使用一个简单的循环使其工作,并简单地丢弃 9/10 值,但这意味着您仍在注册每个事件,只是不将其写入文件,这似乎并不理想。

我的下一个想法是每 1/10 秒使用一次 Runnable,结果只得到一个传感器,而不是两个。

我的下一个想法是为每个传感器创建一个 runnable,并在 runnable 中注册和注销它们中的每一个:

public void registerAccel(){
    Log.d(TAG, "registerAccel: on");
    sensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);

}

public void unregisterAccel(){
    Log.d(TAG, "unregisterAccel: off");
    sensorManager.unregisterListener(this, mAccelerometer);
}



private final Runnable processAccel = new Runnable() {
    @Override
    public void run() {
        Log.d(TAG, "run: AccelStart");

        registerAccel();

        mHandler.postDelayed(this, interval);

        unregisterAccel();

    }
};

这没有产生传感器读数,但我注意到即使可运行对象每 1/10 秒运行一次,但整个可运行对象在 1/1000 秒内完成,但我认为这可能太快而无法注册传感器.所以我加了一个睡眠:

private final Runnable processAccel = new Runnable() {
    @Override
    public void run() {
        Log.d(TAG, "run: AccelStart");

        registerAccel();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        mHandler.postDelayed(this, interval);

        unregisterAccel();

    }
};

这现在让 Runnable 保持打开 1/10 秒,但我仍然没有从传感器接收到任何数据?基本上 onSensorChanged 在 runnable 运行时不会被调用,但是如果我删除:

unregisterAccel();

从 Runnable 开始,它返回到每 1/100 秒接收一次数据。

我在这里碰壁了,我想不出任何其他方法可以每 10 秒读取一次。

请注意,这是一个 24/7 全天候在后台运行的应用程序,因此我正在尽我所能减少电池消耗,我真的希望这会奏效,因为注册然后取消注册传感器看起来像最好的选择,但我想这样做可能需要超过 1/10 秒的时间?

如果有人能发现我的代码有问题,那就太棒了!

编辑: 好的,进一步测试,我想我一定是误解了一些东西。我尝试将 thread.sleep 延长到 10 秒,但仍然没有收到 OnSensorChanged 事件,即使传感器仍处于注册状态。这让我很困惑,因为唯一应该休眠的线程是可运行的,传感器已注册,而 OnSensorChanged 不是可运行的一部分,所以我不确定为什么什么都没有注册?

【问题讨论】:

  • 这种重载能否帮助您提供采样事件的速率? developer.android.com/reference/android/hardware/…
  • 不,我在那里给出的值似乎没有任何区别......它每 1/100 秒记录一次,无论我输入什么值
  • 不同的手机硬件似乎工作方式不同,这是为了科学应用,所以我试图在手机上获得一致的结果。
  • 延迟率不是根据文档来保证的 stackoverflow.com/questions/11685400/… 但是,由于这是用于科学应用,如果采样率失控,您也可以通知用户或禁用该功能
  • 添加了一个编辑,我认为我的 Runnable 代码有问题,因为即使睡眠 Runnable 10 秒我也没有得到任何结果。

标签: android sensors runnable android-sensors


【解决方案1】:

您可以使用全局布尔值(我知道...)来保持状态。比如:

boolean checkSensor = false;

@Override
public void onResume() {
    super.onResume();
    Handler handler = new Handler();
    handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                checkSensor = true;
            }
        }, 100);
}

@Override
public void onSensorChanged(SensorEvent event) {
    if (checkSensor) {
        checkSensor = false;

        // do your stuff
    }
}

【讨论】:

    【解决方案2】:

    您为采样率输入的默认值或值效果很好。我在几台设备上对其进行了测试。可能是你手机的问题。您还可以使用 Android Studio 及其虚拟传感器测试传感器。

    要从另一个线程获取值,您应该使用SensorManager.registerListener(listener, sensor, samplingPeriodUs, handler); 方法,在线程中注册它们不会有帮助,因为 SensorManager 的处理程序是 UI 线程上的处理程序。可以参考这个链接实现register sensor in separate thread

    【讨论】:

      【解决方案3】:

      您可以为此目的使用TimerTimerTask。只是一个例子。

      Timer timer_sensor = new Timer();
      
      TimerTask task_process_sensor = new TimerTask() {
          public void run() {
             //perform your action here
          }
      };
      
      timer_sensor.schedule(task_process_sensor, 0, 100);
      

      100 毫秒是您的周期。

      Timer 的方法调度如下所示:

      void schedule (TimerTask task, 
                      long delay, 
                      long period)
      

      有关详细信息,请参阅计时器文档。

      您应该将传感器值连续存储在Sensorchanged 中的各个变量中,并在每 100 毫秒触发一次时在 TimerTask 中使用它们。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-09-25
        • 1970-01-01
        • 2011-05-08
        • 1970-01-01
        • 2018-12-06
        • 2016-02-03
        相关资源
        最近更新 更多