Reputation: 1235
I am trying to log Android sensor data (Accelerometer, Gyro), every 1/10th of a second. Using the Android supplied values (AI, GAME, NORMAL), or user defined values (eg 100000 microseconds) makes absolutely no difference, onSensorChanged is firing every 1/100th of a second. This is bad for both battery life, and the size of logging files ( 60 million events every day to log).
I can make it work using a simple loop, and simply throwing away 9/10 values, but that means you are still registering every event, just not writing it to file, which does not seem ideal.
My next idea was to use a Runnable every 1/10th of a second, that resulted in only getting one of the sensors, not both.
My next Idea was to have a runnable for each sensor, and register and deregister each of them in the 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();
}
};
This produced no sensor readings, but i noticed even though the runable was running every 1/10th of a second, the whole Runnable was finishing in 1/1000th of a second, which i though might be too fast to register the sensor. So I added a sleep:
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();
}
};
This now keeps the Runnable open for 1/10th of a second, but I am still not receiving any data from the sensors? Basically onSensorChanged is not called while the runnable is running, but if i remove the:
unregisterAccel();
from the Runnable, it goes back to receiving data every 1/100th of a second.
I am hitting a wall here, I can't think of any other way to get a reading every 10th of a second.
Note this is an app that will run in the background 24/7, so I am trying to do everything I can to minimize the battery drain, and I was really hopeful this would work, as registering then unregistering the sensors seems like the best option, but I guess it may just take longer than 1/10 of a second to do so?
If someone could find a problem with my code, that would be awesome!
EDIT: OK on further testing, I think I must be misunderstanding something. I tried extending the thread.sleep out to 10 seconds, and still get no OnSensorChanged events, even though the sensor is still registered. This confuses me, as the only thread that should be sleeping is the runnable, the sensor is registered, and OnSensorChanged is not part of the Runnable, so I am unsure why nothing is registering?
Upvotes: 3
Views: 4109
Reputation: 3355
You can use Timer and TimerTask for this purpose. Just an example.
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 milliseconds is your period here.
Timer's method schedule looks like this:
void schedule (TimerTask task,
long delay,
long period)
For details, see the Timer documentation.
You should store your sensor values continuously in Sensorchanged
in respective variables, and use them in TimerTask when its fired every 100 milliseconds.
Upvotes: 1
Reputation: 67248
Default or values you enter for sampling rate works well. I tested it on several devices. It might be issue with your phone. You can also test sensors with Android Studio and it's virtual sensors.
To get values from another thread you should use SensorManager.registerListener(listener, sensor, samplingPeriodUs, handler);
method, registering them inside a thread won't help since SensorManager's handler is the one on UI thread. You can refer to this link to implement register sensor in separate thread.
Upvotes: 0
Reputation: 1166
You could use a global boolean (I know...) to maintain the status. Something like:
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
}
}
Upvotes: 2