Android同步onSensorChanged?

时间:2016-04-04 10:34:50

标签: java android multithreading synchronization android-sensors

这是我的问题的后续跟踪:Android thread runnable performance

我在应用我的应用程序的同步方法时遇到了一些困难

我正在轮询传感器,并在传感器更改时将传感器值存储到数组中

float[] accelerometerMatrix = new float[3];
float[] accelerometerWorldMatrix = new float[3];
float[] gyroscopeMatrix = new float[3];
float[] gravityMatrix = new float[3];
float[] magneticMatrix = new float[3];
float[] rotationMatrix = new float[9];

class InsertHandler implements Runnable {
        public void run() {
            //get values from arrays and insert into db
        }
    }

public void onSensorChanged(SensorEvent event) {
        sensor = event.sensor;

        int i = sensor.getType();
        if (i == MainActivity.TYPE_ACCELEROMETER) {
            accelerometerMatrix = event.values;
        } else if (i == MainActivity.TYPE_GYROSCOPE) {
            gyroscopeMatrix = event.values;
        } else if (i == MainActivity.TYPE_GRAVITY) {
            gravityMatrix = event.values;
        } else if (i == MainActivity.TYPE_MAGNETIC) {
            magneticMatrix = event.values;
        }

        long curTime = System.currentTimeMillis();
        long diffTime = (curTime - lastUpdate);

        // only allow one update every POLL_FREQUENCY.
        if(diffTime > POLL_FREQUENCY) {
            lastUpdate = curTime;

            //insert into database in background thread
            executor.execute(insertHandler);
        }
    }

每隔10ms,我的应用程序将获取当前传感器值(来自数组)并使用单个线程执行程序将它们插入到数据库中。所以onSensorChanged方法都是写入数组,并从数组中读取以写入数据库

我的问题是,onSensorChanged方法应该同步吗?

最重要的是我不会遗漏任何数据。每隔10ms我需要存储当前的传感器值 - 没有一个可以错过。

因此,据我所知,同步方法意味着UI线程将保持锁定,并将传感器值写入数组。在此期间,执行程序线程无法从锁定中读取这些数组。然后解除锁定,然后执行程序线程锁定,从数组读取,并写入数据库,释放锁定

我可能在这里误解了同步方法的使用,特别是考虑到onSensorChanged是事件驱动的,我不确定它是如何发挥作用的

但似乎在这样的情况下,我可能不会每隔10ms插入最新的值。当UI线程建立锁定时,执行程序线程无法将这些值写入数据库。到执行程序线程可以写入时,这些值现在将是几毫秒且不准确

另一方面,同步意味着我没有UI线程正在更改数组值的情况,而同时执行程序线程将一半更改的值插入数据库

因此,对于需要每隔10ms插入最新/准确的传感器数据的情况,我应该使用同步方法吗?

1 个答案:

答案 0 :(得分:2)

您当前的代码不是线程安全的,因为Runnable使用的是与UI线程正在写入的相同的数组。一旦调用executor.execute(insertHandler);,就不能保证UI线程不会获得另一个传感器事件,并在Runnable将数据值写入数据库之前更改其中一个数组值。看来你理解这部分了。

为了解决这个问题,我不建议使用同步块,因为看起来你只想在diffTime > POLL_FREQUENCY时写出数组中存储的任何值。 onSensorChanged(...)方法本身只会在代码中的UI线程上调用,因此您不必担心在此方法中更改数组值的另一个线程。

所有这些说明你可以做的是将数组的当前值存储在Runnable类的新实例中。我知道您在上一篇文章中建议使用相同的实例,但这不会产生显着的差异。您甚至可以通过打开Android Monitor来验证,并在应用程序运行时检查您的内存使用情况。通过存储当前值,现在在写出数据之前再次调用onSensorChanged()并不重要,因为您已经拥有了所需的数据副本,但不会发生变化。

以下是我在代码中建议的内容:

class InsertHandler implements Runnable {
    final float[] accelerometerMatrix;
    final float[] accelerometerWorldMatrix;
    final float[] gyroscopeMatrix;
    final float[] gravityMatrix;
    final float[] magneticMatrix;
    final float[] rotationMatrix;

    public InsertHandler(float[] accelerometerMatrix, float[] accelerometerWorldMatrix,
            float[] gyroscopeMatrix, float[] gravityMatrix,
            float[] magneticMatrix, float[] rotationMatrix) {
        this.accelerometerMatrix = accelerometerMatrix;
        this.accelerometerWorldMatrix = accelerometerWorldMatrix;
        this.gyroscopeMatrix = gyroscopeMatrix;
        this.gravityMatrix = gravityMatrix;
        this.magneticMatrix = magneticMatrix;
        this.rotationMatrix = rotationMatrix;
    }

    public void run() {
        // use class field arrays values and insert into db
    }
}

然后当您将Runnable添加到executor时使用:

Runnable insertHandler = new InsertHandler(accelerometerMatrix, accelerometerWorldMatrix,
        gyroscopeMatrix, gravityMatrix, magneticMatrix, rotationMatrix);
executor.execute(insertHandler);