设备休眠时,Android会降低前台服务的速度

时间:2019-03-14 19:42:54

标签: android android-sensors

几天来,我一直在以下方面苦苦挣扎:我想在屏幕关闭时使用Android设备上的重力传感器来计算运动模式。我正在使用从前台启动的绑定服务(带有Android 8的通知以使其保持运行),并且在屏幕打开时一切正常。即使该应用程序未在前台运行,也可以正常工作。

但是,一旦显示器关闭,就会发生非常奇怪的事情:传感器数据仍在处理中,并且移动进行了一定程度的扩展,但结果非常糟糕且不准确。另外,如果再次打开屏幕,则该应用程序的行为非常奇怪。有时应用程序会按预期运行,但有时似乎旧传感器事件被延迟处理并在以后进行计数。从那时起,整个算法运行不平稳。有趣的是:如果插入了设备,并且我在Android Studio的控制台中观察到了一切,即使屏幕关闭了,一切也都可以完美运行。但是,如果拔下设备的电源,结果将再次变为错误。

我尝试了很多事情:使用IntentService在主线程,另一个线程上运行所有内容,将Doze的白名单上的应用设置为不关闭屏幕时不向MainActivity发送数据,然后跟随this guide(我正在使用Galaxy J5进行开发)-但没有任何效果。似乎,即使有注册的侦听器,Android系统的SensorFusion算法在Standby中也会关闭,或者Samsung会在后台运行某些电池优化并限制CPU操作。还有其他可能导致此行为的情况吗?因此,如果该应用处于活动状态,处于后台状态,但在设备处于睡眠状态时却无法正常运行,那么运行情况很好吗?

也许还值得一提:我正在为Cordova开发一个插件。

这是我的代码

Main.class

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) {
        ...
    };

}

Service.class

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调试应用程序,即使设备处于休眠状态且屏幕关闭,该应用程序也可以正常运行。调试此问题非常困难,因为即使没有连接电缆,只要我调试该应用程序,它的性能就很好。我不知道还能做什么。

1 个答案:

答案 0 :(得分:1)

对于遇到类似问题的每个人:我终于找到了解决方案。

我认为这在Android文档中没有得到很好的解释,也不是很直观,但是仍然有必要设置部分唤醒锁以防止CPU休眠。 This说明了如何设置唤醒锁。仅前台服务不足以保持时间紧迫的进程运行。