Thread.sleep 应用程序在后台运行时速度变慢

Thread.sleep slow down when application is in background

我正在尝试使用新的 Lolipop Api 创建一个屏幕录像机。 所以,我需要一个快速线程,至少能够以 10 fps 的速度循环。

但是,经过几次测试,我发现了一个问题: 当我的应用程序可见时,线程执行良好。 但是当我切换到另一个应用程序或 android 主屏幕时,线程确实变慢了。 即使在我的线程中没有执行任何操作

我想问题出在 thread.sleep 方法上。 我从 activity 启动这个线程,我已经尝试从服务启动它,结果相同。 不管怎样,我读到服务不是真正的地方,因为它可以随时被系统杀死。

知道如何让我的线程保持反应吗? 或者也许使用线程不是好的解决方案?

这是用于测试的线程:

 /** Thread used to capture images from screen */
  public class ImagesCaptureThread implements Runnable {

    /** fps wanted */
    private final static int _fps = 10;

    /** Delay between images */
    private final static int _delayBetweenImagesInMs = 1000 / _fps;

    /** Date used to calculate fps */
    private Date _fpsDate = null;

    @Override
    public void run() {
      Log.i("My App", "start capturing images");
      _fpsDate = new Date();
      while (true) {
        try {
          long startProcessingTime = new Date().getTime();

          long elapsedTime = new Date().getTime() - _fpsDate.getTime();
          Log.i("My App", "Fps : " + ((1000 * 1.0) / elapsedTime));
          _fpsDate = new Date(); // Re init date

          if (!_captureStarted) { // Stop capturing
            Log.i("My App", "stop capturing images");
            break;
          }

          // TO DO : Capture image

          // Calculate how many time we need to sleep before next image capture
          long processingTime = new Date().getTime() - startProcessingTime;
          long sleepTime = _delayBetweenImagesInMs - processingTime;
          if (sleepTime > 0) {
            Thread.sleep(sleepTime);
          }
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    }
  }

我得到的日志:

02-17 00:39:39.291: I/My App(28012): start capturing images
02-17 00:39:39.392: I/My App(28012): Fps : 9.900990099009901
02-17 00:39:39.492: I/My App(28012): Fps : 10.0
02-17 00:39:39.592: I/My App(28012): Fps : 10.0
02-17 00:39:39.693: I/My App(28012): Fps : 9.900990099009901
02-17 00:39:39.793: I/My App(28012): Fps : 10.0
02-17 00:39:39.893: I/My App(28012): Fps : 10.0
02-17 00:39:39.994: I/My App(28012): Fps : 9.900990099009901
02-17 00:39:40.094: I/My App(28012): Fps : 10.0
02-17 00:39:40.194: I/My App(28012): Fps : 10.0
 [ THIS IS WHEN I SWITCH TO ANDROID HOME SCREEN ]
02-17 00:39:42.040: I/My App(28012): Fps : 7.194244604316546
02-17 00:39:42.176: I/My App(28012): Fps : 7.407407407407407
02-17 00:39:42.312: I/My App(28012): Fps : 7.462686567164179
02-17 00:39:42.450: I/My App(28012): Fps : 7.246376811594203
02-17 00:39:42.590: I/My App(28012): Fps : 7.142857142857143
02-17 00:39:42.731: I/My App(28012): Fps : 7.142857142857143
02-17 00:39:42.867: I/My App(28012): Fps : 7.407407407407407
 [ THEN I SWITCH BACK TO MY APPLICATION ]
02-17 00:39:44.731: I/My App(28012): Fps : 9.900990099009901
02-17 00:39:44.831: I/My App(28012): Fps : 10.0
02-17 00:39:44.931: I/My App(28012): Fps : 10.0
02-17 00:39:45.032: I/My App(28012): Fps : 10.0
02-17 00:39:45.131: I/My App(28012): Fps : 10.1010101010101
02-17 00:39:45.231: I/My App(28012): Fps : 10.0
02-17 00:39:46.234: I/My App(28012): stop capturing images

好的,所以我很确定 Service 是比使用线程更好的选择。根据 Android 文档:

Because a process running a service is ranked higher than a process with background activities, an activity that initiates a long-running operation might do well to start a service for that operation, rather than simply create a worker thread—particularly if the operation will likely outlast the activity. For example, an activity that's uploading a picture to a web site should start a service to perform the upload so that the upload can continue in the background even if the user leaves the activity. Using a service guarantees that the operation will have at least "service process" priority, regardless of what happens to the activity.

有关进程(服务、活动)和线程(及其优先级)的更多信息here. Services can be background and foreground, read a bit more about them here(这可能会帮助您确定您是否实施了错误,以便您可以修复它)。

至于您的具体问题,请尝试检查 sleepTime 值,这可能存在一些问题(不幸的是,我无法测试您的示例,但我会先检查该值),如果您还是找不到问题所在,那么你应该尝试使用Systrace or Traceview检查你的应用程序性能,并找出为什么当应用程序不可见时fps较低...

我不是 Android 开发人员,但在我看来 OS 只是没有按照您希望的速度安排您的线程执行...事件的顺序看起来像这样:

  • 您的主题是 运行
  • 您的线程调用 Thread.sleep(X)
  • OS 暂停您的线程
  • X 毫秒过去了,您的线程现在又是 "executable/runnable"
  • OS 有另一个 Y 线程需要安排在 CPU 上执行。选择您的线程并给出 CPU 个周期需要 Z 毫秒。

似乎 Android 给予来自后台应用程序的线程低得多的优先级,这导致在您的线程开始执行之前似乎有 Z=36 毫秒的延迟。

解决此问题的一种方法是减少睡眠并在需要时跳过迭代。例如,您可以休眠 sleepTime/10 毫秒,并且在每次迭代时检查是否应该进行帧捕获。