将加速度计传感器数据写入文件时出错
Writing accelerometer sensor data to file is out of order
我正在开发一个 Android 应用程序,它将时间戳和 3 轴加速计传感器数据(时间戳、ax、ay、az)写入 csv 文件。我首先遇到两个问题,少数条目的时间戳没有按升序写入文件(请参见图像中黄色突出显示的时间戳)。
其次,我得到了一个时间戳的许多条目(不是重复的条目),理想情况下我们应该只得到一个唯一时间戳的条目 。
我的应用程序的设计是:我正在创建一个服务,它将 运行 在后台运行并将所有传感器数据记录到一个文件中。我正在使用 ZipOutputStream 包装 BufferedOutputStream 和 FileOutputStream 将传感器数据写入文件。下面是 AccelerometerLoggingService
的代码片段。我正在 onDestroy()
服务方法中关闭文件。你能告诉我我的代码或设计中可能存在的缺陷是什么吗?我认为线程可能存在一些问题,但我不知道如何调试它。感谢任何帮助。
public class AccelerometerLoggingService extends Service {
class AccelerometerEventLoggerTask extends AsyncTask<Acceleration, Void, Void> {
@Override
protected Void doInBackground(Acceleration... accelerations) {
Acceleration acc = accelerations[0];
writeAcceleration(acc);
return null;
}
}
class AccelerometerSensorListener implements SensorEventListener {
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER)
return;
Acceleration acc = new Acceleration(System.currentTimeMillis(),
event.values[0],
event.values[1],
event.values[2]);
new AccelerometerEventLoggerTask().execute(acc);
}
}
}
writeAcceleration(Acceleration acc) {
zipOutputStream.write(acc.toString().getBytes());
}
//
ZipOutputStream zipOutputStream = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(logFile)));
更新 2:
我以为是线程同步问题。因此,我决定 运行 加速度计传感器在单独的后台线程上,并将传感器数据写入同一线程中的文件,但我的文件中的条目仍然乱序。以下是我所做的新代码更改。
public void startAccelerometer() {
// creating new thread for onSensorChanged method to run
handlerThread = new HandlerThread("AccelerometerSensorThread");
handlerThread.start();
handler = new Handler(handlerThread.getLooper());
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
mAccelerometerSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mSensorManager.registerListener(this, mAccelerometerSensor, SensorManager
.SENSOR_DELAY_GAME, handler);
}
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER)
return;
Acceleration acc = new Acceleration(System.currentTimeMillis(),
event.values[0],
event.values[1],
event.values[2]);
accelerometerLogger.writeAcceleration(acc); // writing sensor data to file
Log.d(TAG, "onSensorChanged Thread name " + Thread.currentThread().getName()); // AccelerometerSensorThread
}
public void stopAccelerometer() {
// first unregister the sensor listener then stop the thread
mSensorManager.unregisterListener(this);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
handlerThread.quitSafely();
} else {
handlerThread.quit();
}
}
尝试以下(添加 synchronized
块)
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER)
return;
synchronized(this) {
Acceleration acc = new Acceleration(System.currentTimeMillis(),
event.values[0],
event.values[1],
event.values[2]);
new AccelerometerEventLoggerTask().execute(acc);
}
}
问题似乎与事件的写入顺序无关。获得 "out of order" 时间戳后,后续时间将从新时间戳而不是旧时间戳继续增加。可能发生的情况是您的蜂窝网络正在重置系统时间 https://developer.android.com/reference/android/os/SystemClock.html。
解决方案取决于您的要求。在这种情况下,您可以记住上次写入的时间并丢弃该时间之前的任何传感器读数。或者,您可以使用 uptimeMillis() 方法将时间戳调整为相对于开始记录的时间。
我正在开发一个 Android 应用程序,它将时间戳和 3 轴加速计传感器数据(时间戳、ax、ay、az)写入 csv 文件。我首先遇到两个问题,少数条目的时间戳没有按升序写入文件(请参见图像中黄色突出显示的时间戳)。
其次,我得到了一个时间戳的许多条目(不是重复的条目),理想情况下我们应该只得到一个唯一时间戳的条目
我的应用程序的设计是:我正在创建一个服务,它将 运行 在后台运行并将所有传感器数据记录到一个文件中。我正在使用 ZipOutputStream 包装 BufferedOutputStream 和 FileOutputStream 将传感器数据写入文件。下面是 AccelerometerLoggingService
的代码片段。我正在 onDestroy()
服务方法中关闭文件。你能告诉我我的代码或设计中可能存在的缺陷是什么吗?我认为线程可能存在一些问题,但我不知道如何调试它。感谢任何帮助。
public class AccelerometerLoggingService extends Service {
class AccelerometerEventLoggerTask extends AsyncTask<Acceleration, Void, Void> {
@Override
protected Void doInBackground(Acceleration... accelerations) {
Acceleration acc = accelerations[0];
writeAcceleration(acc);
return null;
}
}
class AccelerometerSensorListener implements SensorEventListener {
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER)
return;
Acceleration acc = new Acceleration(System.currentTimeMillis(),
event.values[0],
event.values[1],
event.values[2]);
new AccelerometerEventLoggerTask().execute(acc);
}
}
}
writeAcceleration(Acceleration acc) {
zipOutputStream.write(acc.toString().getBytes());
}
//
ZipOutputStream zipOutputStream = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(logFile)));
更新 2:
我以为是线程同步问题。因此,我决定 运行 加速度计传感器在单独的后台线程上,并将传感器数据写入同一线程中的文件,但我的文件中的条目仍然乱序。以下是我所做的新代码更改。
public void startAccelerometer() {
// creating new thread for onSensorChanged method to run
handlerThread = new HandlerThread("AccelerometerSensorThread");
handlerThread.start();
handler = new Handler(handlerThread.getLooper());
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
mAccelerometerSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mSensorManager.registerListener(this, mAccelerometerSensor, SensorManager
.SENSOR_DELAY_GAME, handler);
}
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER)
return;
Acceleration acc = new Acceleration(System.currentTimeMillis(),
event.values[0],
event.values[1],
event.values[2]);
accelerometerLogger.writeAcceleration(acc); // writing sensor data to file
Log.d(TAG, "onSensorChanged Thread name " + Thread.currentThread().getName()); // AccelerometerSensorThread
}
public void stopAccelerometer() {
// first unregister the sensor listener then stop the thread
mSensorManager.unregisterListener(this);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
handlerThread.quitSafely();
} else {
handlerThread.quit();
}
}
尝试以下(添加 synchronized
块)
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER)
return;
synchronized(this) {
Acceleration acc = new Acceleration(System.currentTimeMillis(),
event.values[0],
event.values[1],
event.values[2]);
new AccelerometerEventLoggerTask().execute(acc);
}
}
问题似乎与事件的写入顺序无关。获得 "out of order" 时间戳后,后续时间将从新时间戳而不是旧时间戳继续增加。可能发生的情况是您的蜂窝网络正在重置系统时间 https://developer.android.com/reference/android/os/SystemClock.html。
解决方案取决于您的要求。在这种情况下,您可以记住上次写入的时间并丢弃该时间之前的任何传感器读数。或者,您可以使用 uptimeMillis() 方法将时间戳调整为相对于开始记录的时间。