10

我正在学习 Android 编程基础知识。

我有一个简单的 android 测试应用程序,在其中我将加速度计、磁力计和方向数据记录到外部文件,同时也显示它。我通过调用方法initLogger单击开始按钮(相关传感器的 registerListener)启动日志记录过程。

看起来与此类似...

public void initLogger(View view)
{
    boolean bFlag = false;

    Button btnStart = (Button)findViewById(R.id.btnStartLog);
    Button btnStop = (Button)findViewById(R.id.btnStopLog);

    btnStart.setEnabled(bFlag);
    btnStop.setEnabled(!bFlag);

    bEnableLogging = true;
    //Start reading the sensor values
    sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD), SensorManager.SENSOR_DELAY_UI);
    sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_UI);

   //so on.... 

还有一个停止按钮,它将停止记录过程(最后通过为每个传感器调用 unregisterListener 来取消注册)

数据检索过程发生在onSensorChanged处理程序内部,该处理程序应从相关传感器检索数据,将值设置为相应的 UI 元素,最后将数据记录到外部 .csv 文件中。

onSensorChanged事件处理程序看起来像这样......

public void onSensorChanged(SensorEvent event) {


    // TODO Auto-generated method stub
    // accelerometer
    TextView tAX = (TextView) findViewById(R.id.txtViewAxValue);
    TextView tAY = (TextView) findViewById(R.id.txtViewAyValue);
    TextView tAZ = (TextView) findViewById(R.id.txtViewAzValue);

    // magnetic field
    TextView tMX = (TextView) findViewById(R.id.txtViewMx);
    TextView tMY = (TextView) findViewById(R.id.txtViewMy);
    TextView tMZ = (TextView) findViewById(R.id.txtViewMz);

    if (bEnableLogging) {
        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {

            accelerometerdata = event.values.clone();

            tAX.setText(Double.toString(accelerometerdata[0]));
            tAY.setText(Double.toString(accelerometerdata[1]));
            tAZ.setText(Double.toString(accelerometerdata[2]));


        }

        if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {

            magneticmatrixdata = event.values.clone();

            tMX.setText(Double.toString(magneticmatrixdata[0]));
            tMY.setText(Double.toString(magneticmatrixdata[1]));
            tMZ.setText(Double.toString(magneticmatrixdata[2]));

        }

               // so on ....

虽然我从所有配置的传感器接收数据,但我无法控制接收数据的速率。IE

我知道 SensorChanged 事件是在传感器数据更改时触发的。但是,我希望以固定的速率触发此事件。例如:每 40 毫秒

问题:

  1. 如何确保 SensorChanged 事件以恒定速率触发?
  2. 在这种情况下,Java 中的 TimerTask 类有什么帮助吗?

SO的专家在这里。请帮助我:)

4

5 回答 5

3

您可以通过更改注册传感器时的延迟来更改间隔。

int SENSOR_DELAY_FASTEST    get sensor data as fast as possible 
int SENSOR_DELAY_GAME       rate suitable for games 
int SENSOR_DELAY_NORMAL     rate (default) suitable for screen orientation changes
int SENSOR_DELAY_UI         rate suitable for the user interface

据此最快的延迟是您需要的,如果它对您来说变化不够快,是因为没有变化。没有 getSensorData 方法。

您可以指定其他数据延迟,例如 SENSOR_DELAY_GAME(20,000 微秒延迟)、SENSOR_DELAY_UI(60,000 微秒延迟)或 SENSOR_DELAY_FASTEST(0 微秒延迟)。从 Android 3.0(API 级别 11)开始,您还可以将延迟指定为绝对值(以微秒为单位)。

您指定的延迟只是建议的延迟。Android 系统和其他应用程序可以更改此延迟。作为最佳实践,您应该尽可能指定最大延迟,因为系统通常使用比您指定的延迟更小的延迟(也就是说,您应该选择仍能满足应用程序需求的最慢采样率)。使用更大的延迟会降低处理器的负载,因此使用更少的功率。

于 2012-09-03T11:40:07.937 回答
2

既然您知道如果没有触发 SensorChanged 事件,则没有任何更改,您可以使用旧值。当您要求以特定间隔提供 LOG 数据时,我不会在 onSensorChanged 方法中执行任何输出,只是将新数据克隆到您的 accelerometerdata 变量中。并且每 40 毫秒记录一次 accelerometerdata 的值。这样,即使数据没有改变,您也每 40 毫秒记录一次实际值......

注意:根据 Ridcullys 的回答,似乎也可以在特定的时间间隔内“传递”传感器数据。但由于这些“交付”与 Android 上的传感器数据一样存在延迟,因此使用我的解决方案,您将更准确地处于 40 毫秒间隔。另一方面,如果传感器数据在您登录的那一刻发生变化,您可能会将新数据延迟一个时间间隔。而且我猜(不确定这一点) - 因为它只是关于日志记录而不是像“尽可能快地实时获取它”这样的东西,所以这不是必需的 - 定时器解决方案导致更少的 CPU 负载。

于 2012-09-05T07:04:29.543 回答
1

SensorManager使用registerListener注册侦听器时,SENSOR_DELAY_...您可以按照 JavaDocs 中的说明传递以微秒为单位的间隔,而不是固定常量:

rate 速率传感器事件的传送速度。这只是对系统的提示。事件的接收速度可能比指定的速率快或慢。通常会更快地接收到事件。该值必须是 SENSOR_DELAY_NORMAL、SENSOR_DELAY_UI、SENSOR_DELAY_GAME 或 SENSOR_DELAY_FASTEST 之一,或者是所需的事件之间的延迟(以微秒为单位)。

因此,只需传递40000以匹配您的示例请求,而且,如前所述,这只是一个提示,因此我不会依赖于以精确到微秒的间隔获取值。

于 2012-09-03T12:37:09.643 回答
0

我一直在试图弄清楚如何才能让传感器有很长的延迟,到目前为止我已经成功了。developer.android 上的文档谈到延迟时间可以以微秒为单位指定,以下是我尝试过的大量:

// Initialize in onCreate
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE)
mLight = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);

// Register the listener, and play around with delay
mSensorManager.registerListener(this, mLight, 200000000);

但是请注意下面的 LogCat 转储 - onSensorChanged() - 每秒被调用多达 4 次......我试图找出更大的延迟,但到目前为止没有成功!!!

01-14 06:58:07.088: D/IOE Sensors(20933): onSensorChanged 调用,事件是: android.hardware.SensorEvent@42849f70 01-14 06:58:07.268: D/IOE Sensors(20933): onSensorChanged 调用, 事件为: android.hardware.SensorEvent@42849f70 01-14 06:58:07.448: D/IOE Sensors(20933): onSensorChanged 调用, 事件为: android.hardware.SensorEvent@42849f70 01-14 06:58: 07.628: D/IOE Sensors(20933): onSensorChanged 被调用,事件为:android.hardware.SensorEvent@42849f70 01-14 06:58:07.808: D/IOE Sensors(20933): onSensorChanged 被调用,事件为:android. hardware.SensorEvent@42849f70 01-14 06:58:07.989: D/IOE Sensors(20933): onSensorChanged 调用,事件是: android.hardware.SensorEvent@42849f70 01-14 06:58:08.169: D/IOE Sensors( 20933): onSensorChanged 调用,事件为:android.hardware.SensorEvent@42849f70

于 2014-01-14T14:17:56.393 回答
0

似乎调用 onSensorChanged 的​​速率必须是 4 个建议值之一。

对于“慢速读取”,您可以使用 SENSOR_DELAY_UI 并(在 onSensorChanged 中)测量自上次读取传感器数据以来经过的时间:

long lastUpdate = System.currentTimeMillis();

// In onSensorChanged:
long curTime = System.currentTimeMillis();

        if ((curTime - lastUpdate) > 500){ // only reads data twice per second
            lastUpdate = curTime;
            // do stuff
        }

我在这里看到的唯一缺点是 if 语句将被多次调用,结果是错误的。

于 2015-07-20T00:45:02.333 回答