几天来,我一直在以下方面苦苦挣扎:我想在屏幕关闭时使用Android设备上的重力传感器来计算运动模式。我正在使用从前台启动的绑定服务(带有Android 8的通知以使其保持运行),并且在屏幕打开时一切正常。即使该应用程序未在前台运行,也可以正常工作。
但是,一旦显示器关闭,就会发生非常奇怪的事情:传感器数据仍在处理中,并且移动进行了一定程度的扩展,但结果非常糟糕且不准确。另外,如果再次打开屏幕,则该应用程序的行为非常奇怪。有时应用程序会按预期运行,但有时似乎旧传感器事件被延迟处理并在以后进行计数。从那时起,整个算法运行不平稳。有趣的是:如果插入了设备,并且我在Android Studio的控制台中观察到了一切,即使屏幕关闭了,一切也都可以完美运行。但是,如果拔下设备的电源,结果将再次变为错误。
我尝试了很多事情:使用IntentService在主线程,另一个线程上运行所有内容,将Doze的白名单上的应用设置为不关闭屏幕时不向MainActivity发送数据,然后跟随this guide(我正在使用Galaxy J5进行开发)-但没有任何效果。似乎,即使有注册的侦听器,Android系统的SensorFusion算法在Standby中也会关闭,或者Samsung会在后台运行某些电池优化并限制CPU操作。还有其他可能导致此行为的情况吗?因此,如果该应用处于活动状态,处于后台状态,但在设备处于睡眠状态时却无法正常运行,那么运行情况很好吗?
也许还值得一提:我正在为Cordova开发一个插件。
这是我的代码
public class SensorPlugin extends CordovaPlugin implements ServiceClass.Delegate {
public void initialize() {
...
Intent serviceIntent = new Intent(applicationContext, ServiceClass.class);
applicationContext.bindService(serviceIntent, serviceConnection,
Context.BIND_AUTO_CREATE);
}
public void start() {
serviceClass.startMeasuring();
}
@Override
public void updateMovementCount(int count) {
...
};
}
public class ServiceClass extends Service implements OtherClass.Delegate {
private volatile boolean isMeasuring;
private volatile double gravityX;
private volatile double gravityY;
private volatile double gravityZ;
public IBinder onBind(Intent intent) {
sensorManager = (SensorManager) getApplicationContext().
getSystemService(Context.SENSOR_SERVICE);
startForeground(1, buildNotification());
return mBinder;
}
public void startMeasuring() {
assert sensorManager != null;
Sensor gravity = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);
sensorManager.registerListener(this, gravity,
SensorManager.SENSOR_DELAY_GAME);
isTracking = true;
SensorThread sensorThread = new SensorThread();
sensorThread();
}
@Override
public void onSensorChanged(SensorEvent event) {
gravityX = event.values[0];
gravityY = event.values[1];
gravityZ = event.values[2];
}
// This is an interface method from another class that I wrote
// (see below). For which I set this class as delegate and as soon
// as the other class finds a pattern in the data it calls this method
@Override
public void movementPatternDidChange(int count) {
// Usually I send this count to the main class with
// the same delegation pattern
delegate.updateMovementCount(count);
}
class SensorProcessingThread extends Thread {
Handler handler = new Handler();
// I use another runnable here, as I only want to process 10
// sensor events per second. The sensor manager usually returns
// way more which I don't need.
private Runnable sensorProcessingRunnable = new Runnable() {
public void run() {
otherClass.processMotionData(gravityX, gravityY, gravityZ);
if (isMeasuring) {
handler.postDelayed(this, 100);
}
}
};
@Override
public void run() {
if (!isMeasuring) {
return;
}
handler.postDelayed(sensorProcessingRunnable, 100);
}
}
}
与此同时,我做了很多测试。我现在使用Apache Commons Primitives Collections以获得更好的性能(而不是大型的FastUtil过去也导致this错误)。
我还在两台设备上测试了该应用程序,它们是相当老的LG G2和Galaxy J5。两者的问题是相同的。因此可能不是特定于制造商的。 Android Studio Profiler报告这两种设备上的CPU使用率平均为1-3%,因此我认为可能不是造成过载的原因。我还测试了TimerTask和Timer而不是Runnable和Handler,但效果不佳。
还有一点很有趣:我尝试通过Wifi as explained here调试应用程序,即使设备处于休眠状态且屏幕关闭,该应用程序也可以正常运行。调试此问题非常困难,因为即使没有连接电缆,只要我调试该应用程序,它的性能就很好。我不知道还能做什么。
答案 0 :(得分:1)
对于遇到类似问题的每个人:我终于找到了解决方案。
我认为这在Android文档中没有得到很好的解释,也不是很直观,但是仍然有必要设置部分唤醒锁以防止CPU休眠。 This说明了如何设置唤醒锁。仅前台服务不足以保持时间紧迫的进程运行。