android - 如何在屏幕关闭的情况下在 Android 上获取传感器和 gnss 数据?
问题描述
我正在开发一个应用程序,我想用它来为数据库和未来的数据科学应用程序收集传感器/GNSS 数据。我想收集更长的时间(至少一个小时)的数据,我想包括不同的情况,比如把手机放在口袋里或背包里。因此,我需要能够让应用程序在屏幕关闭的情况下在后台运行。
我正在使用以下手机:运行 Android 10 或 11 的 Galaxy S20、Pixel 2 和 4 以及 POCOFONE 2。
我已经实现了一项服务,禁用了电池优化,尝试使用唤醒锁并尝试使用包含广播接收器的解决方法,该广播接收器在 ACTION_SCREEN_OFF 上重新注册传感器。这一切只持续了大约五分钟,然后数据就停止了。一旦我重新打开屏幕,数据就会再次出现。
任何想法都非常感谢您提前谢谢。
这是我的主要活动代码:
@RequiresApi(api = Build.VERSION_CODES.R)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Spinner mFrequencySpinner = findViewById(R.id.frequency_spinner);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, R.array.frequency_array, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mFrequencySpinner.setAdapter(adapter);
mFrequencySpinner.setOnItemSelectedListener(this);
//------------------------------------------
// TODO: export to an own fragment later
mLabelGrid = findViewById(R.id.labels_grid);
imageModelList = populateList();
labelAdapter = new LabelAdapter(getApplicationContext(), imageModelList);
mLabelGrid.setAdapter(labelAdapter);
mLabelGrid.setOnItemClickListener((parent, view, position, id) -> setMeanOfTransport(view, position));
//------------------------------------------
}
@Override
protected void onStart() {
super.onStart();
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) !=
PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_PERMISSION_CODE);
}
final boolean gpsEnabled = mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
if (!gpsEnabled) {
DialogFragment dialog = new EnableLocationDialogFragment();
dialog.show(getSupportFragmentManager(), "EnableLocationDialogFragment");
}
}
public void startBackgroundService(View view) {
appStartTime = System.currentTimeMillis();
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DLR_KN_MOBILITY_APP:WAKE_LOCK");
mWakeLock.acquire(15*60*10000L /*150 minutes*/);
Button btn = (Button) view;
if ( !backgroundLogging ) {
backgroundLogging = true;
btn.setText(getResources().getString(R.string.stop_service));
toggleBackgroundService(true);
} else {
btn.setText(getResources().getString(R.string.start_service));
toggleBackgroundService(false);
backgroundLogging = false;
mWakeLock.release();
}
}
private void toggleBackgroundService(boolean on) {
if (!backgroundLogging) return;
if (on) {
Intent serviceIntent = new Intent(this, DataCollectorService.class);
serviceIntent.putExtra("startTime", appStartTime);
serviceIntent.putExtra("samplingFrequency", samplingFrequency);
serviceIntent.putExtra("meanOfTrans", meanOfTrans);
startService(serviceIntent);
} else {
stopService(new Intent(this, DataCollectorService.class));
}
}
这是我的服务代码:
@RequiresApi(api = Build.VERSION_CODES.R)
@Override
public void onCreate() {
super.onCreate();
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
mLogger = new MyLogger(this);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mGyroscope = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
mMagnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
}
@RequiresApi(api = Build.VERSION_CODES.R)
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (initial) {
appStartTime = intent.getLongExtra("startTime", 0);
samplingFrequency = intent.getIntExtra("samplingFrequency", 10000);
registerSensors();
initial = false;
}
meanOfTrans = intent.getIntExtra("meanOfTrans", 0);
return Service.START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
@Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(mReceiver);
disableSensors();
}
@RequiresApi(api = Build.VERSION_CODES.R)
private void registerSensors() {
if (mAccelerometer != null) {
mSensorManager.registerListener(this, mAccelerometer, samplingFrequency);
}
if (mGyroscope != null) {
mSensorManager.registerListener(this, mGyroscope, samplingFrequency);
}
if (mMagnetometer != null) {
mSensorManager.registerListener(this, mMagnetometer, samplingFrequency);
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) ==
PackageManager.PERMISSION_GRANTED) {
mLocationManager.registerGnssMeasurementsCallback(gnssMeasurementsEventListener);
mLocationManager.addNmeaListener(nmeaMessageListener);
}
}
private void disableSensors() {
mSensorManager.unregisterListener(this);
mLocationManager.unregisterGnssMeasurementsCallback(gnssMeasurementsEventListener);
mLocationManager.removeNmeaListener(nmeaMessageListener);
}
@Override
public void onSensorChanged(SensorEvent event) {
double time = event.timestamp*1E-9;
float seconds = ( (float) (System.currentTimeMillis() - appStartTime) ) / 1000;
int sensorType = event.sensor.getType();
String logOut= "";
String sens = "";
switch (sensorType) {
case Sensor.TYPE_ACCELEROMETER:
sens = "ACC";
break;
case Sensor.TYPE_GYROSCOPE:
sens = "GYR";
break;
case Sensor.TYPE_MAGNETIC_FIELD:
sens = "MAG";
break;
}
logOut += getResources().getString(R.string.sample_format, sens, seconds, time, meanOfTrans, isGtp, event.values[0], event.values[1], event.values[2], event.accuracy);
isGtp = false;
mLogger.logSensor(logOut);
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) { }
private final OnNmeaMessageListener nmeaMessageListener = new OnNmeaMessageListener() {
@Override
public void onNmeaMessage(String message, long timestamp) {
mLogger.onNmeaReceived(timestamp, message);
}
};
private final GnssMeasurementsEvent.Callback gnssMeasurementsEventListener =
new GnssMeasurementsEvent.Callback() {
@Override
public void onGnssMeasurementsReceived(GnssMeasurementsEvent event) {
GnssClock gnssClock = event.getClock();
for (GnssMeasurement measurement : event.getMeasurements()) {
mLogger.writeGnssMeasurementToFile(gnssClock, measurement);
}
}
@Override
public void onStatusChanged(int status) {}
};
}
解决方案
推荐阅读
- node.js - chrome 中的 ES6 模块:ERR_ABORTED 404(未找到)
- php - 如何在 PHP 中使用 Mongo 查询?
- r - 删除字符串的开头和结尾,直到它在 R 中找到一个模式
- c# - 在 Unity 中拍摄动画
- deep-learning - 具有可变长度输入的时间序列预测
- angular - 无法在角度 7 中路由到孩子
- c# - 在 DomainUpDown 中将文本转换为数字
- sql - 在 Oracle 12c 中遇到符号 v_PrepareStmt
- c# - 有没有办法防止 ListViewItems 变成 MS.Internal.NamedObject 或从中恢复
- mysql - 如何两次加入同一个表