我目前正在开发一个应用程序,它应该每两秒收集一次加速计和麦克风数据。为此,我启动了一项服务(在里面运行一个计时器),以便在应用程序在后台运行时收集数据。到目前为止一切都很好。
计时器启动,收集数据并将该数据写入XML文件。但是在看了制作的XML文件后,我意识到,当手机处于空闲状态时,加速度计值总是一样的。我甚至使用唤醒锁定,以便每两秒“唤醒”一次电话,但即使这样也无效。
以下是相关代码:
@Override
public void onCreate() {
super.onCreate();
Toast.makeText(this, "Background Service Created", Toast.LENGTH_SHORT)
.show();
Log.d(TAG, "onCreate Service");
this.startActivities();
}
@Override
public void onDestroy() {
super.onDestroy();
// Kill timer, sensors and XML file
this.stopActivities();
Toast.makeText(this, "Background Service Stopped", Toast.LENGTH_SHORT)
.show();
Log.d(TAG, "onDestroy");
}
@Override
public void onStart(Intent intent, int startid) {
Toast.makeText(this, "Background Service Started", Toast.LENGTH_SHORT).show();
Log.d(TAG, "onStart");
}
/**
* Expanded modification function.
*/
private void startExpandedNotification(){
//Id for the intent of the expanded notification
final int myID = 1234;
//The intent to launch when the user clicks the expanded notification
Intent i = new Intent(this, MainMovement.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pendIntent = PendingIntent.getActivity(this, 0, i, 0);
//This constructor is deprecated. Use Notification.Builder instead if programming for 3.0+
Notification notice = new Notification(R.drawable.ic_launcher, "Movement Sampling Activated", System.currentTimeMillis());
//This method is deprecated. Use Notification.Builder instead if programming for 3.0+
notice.setLatestEventInfo(this, "Movement Sampling", "Sensors activated", pendIntent);
notice.flags |= Notification.FLAG_NO_CLEAR;
startForeground(myID, notice);
}
/**
* Stop Expanded Notification
*/
private void stopExpandedNotification(){
stopForeground(true);
}
/**
* Starts everything that the service needs to collect the sensors data
* (timer, xml file, sensors, expanded notification)
*/
private void startActivities() {
// Define output file path
OUTPUT_FILE = Environment.getExternalStorageDirectory()
.getAbsolutePath() + "/Ze";// also added ""/Ze here
OUTPUT_FILE += "/audiorecordtest.3gp";
timer = new Timer(); // If I take this line out, it will lead to an
// exception. But if I do so, the acc values are
// measured while the phone is in the idle state (works only on samsung spika)
timer.scheduleAtFixedRate(new mainTask(), 0, _refreshRate);
xml = new DataStore();
this.startRecordingMic();
this.startRecordingAcc();
startExpandedNotification();
_sampling = true;
}
/**
* Stops everything that the service needs to collect the sensors data
* (timer, xml file, sensors, expanded notification)
*/
private void stopActivities() {
timer.cancel();
//Log.e(TAG, "timer: CANCELLED");
// close xml file
xml.closeFile();
//Log.e(TAG, "XML: CLOSED");
// unregister sensor
_sensorManager.unregisterListener(accelerationListener);
//Log.e(TAG, "Sensors: UNREGISTERED");
// stop recording
if (_recorder != null) {
_recorder.stop();
_recorder.release();
_recorder = null;
}
stopExpandedNotification();
_sampling = false;
}
/**
* Responsible for collecting the sensors data every two seconds
*/
private class mainTask extends TimerTask {
/**
* Collects the sensor data every 2 seconds
*/
@Override
public void run() {
MovementService.this.collectData();
}
}
/**
* Initiates the microphone in order to collect the amplitude value
*/
private void startRecordingMic() {
_recorder = new MediaRecorder();
_recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
_recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
_recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
_recorder.setOutputFile(OUTPUT_FILE);
try {
_recorder.prepare();
} catch (final IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (final IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
_recorder.start();
}
/**
* Initiates the acceleromenter sensor in order to collect movement data
*/
private void startRecordingAcc() {
// ACCELEROMETER
_sensorManager = (SensorManager) this
.getSystemService(Context.SENSOR_SERVICE);
_accelerometer = _sensorManager
.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
_sensorManager.registerListener(accelerationListener, _accelerometer,
SensorManager.SENSOR_DELAY_FASTEST);
}
private final SensorEventListener accelerationListener = new SensorEventListener() {
public void onAccuracyChanged(Sensor sensor, int acc) {
}
public void onSensorChanged(SensorEvent event) {
// sampling values per axis
_x = event.values[0];
_y = event.values[1];
_z = event.values[2];
//Log.e(TAG , "x: " + _x + " y: " + _y + " z:" + _z);
}
};
/**
* Send data (amplitude and decibel) to the xml file
*/
public void collectData() {
//The power lock ensures that the service will indeed collect the accelerometer data
PowerManager pm = (PowerManager) MovementService.this.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "YOUR TAG");
wl.acquire();
Log.v(TAG, "lock aquired");
if (xml != null) xml.writeOnFile(this.getAmplitude(), this.getAccelaration(), this.getTotalAccelaration());
wl.release();
Log.v(TAG, "lock released");
}
你们有什么建议才能解决这个问题吗?这让我发疯了。
Ps:我正在使用三星spika,Android 2.1版。
答案 0 :(得分:0)
AFAIK当设备空闲时,无法对加速度计进行采样。您需要设置一个PARTIAL_WAKE_LOCK来保持CPU运行。它仍然允许屏幕关闭,但当然,电池将比平时更快地耗尽。
http://developer.android.com/reference/android/os/PowerManager.html#PARTIAL_WAKE_LOCK
代码:
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "My Tag");
wl.acquire();
// ..screen will stay on during this section..
wl.release();
您还必须在清单中包含此权限条目:
<uses-permission android:name="android.permission.WAKE_LOCK" />
关于这一点,有一个先前的问题: How to sample accelerometer data in the background or on the sleep mode