当应用程序在后台时,Thread.sleep变慢

时间:2015-02-17 21:36:31

标签: java android multithreading background

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

然而,经过几次测试后,我发现了一个问题: 当我的应用程序可见时,该线程表现良好。 但是当我切换到另一个应用程序或Android主屏幕时,线程真的变慢了。 甚至没有在我的线程中执行任何操作

我认为问题来自thread.sleep方法。 我从一个活动中启动了这个帖子,我已经尝试从一个服务启动它,结果相同。 无论如何,我读到服务并不是真正的地方,因为它可以随时被系统杀死。

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

以下是用于测试的线程:

 /** 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

2 个答案:

答案 0 :(得分:0)

我不是Android开发人员,但在我看来,操作系统并没有像你想的那样快速安排你的线程执行......事件的顺序如下:

  • 您的主题正在运行
  • 您的主题调用Thread.sleep(X)
  • 操作系统暂停您的主题
  • X ms传递,你的线程现在是"可执行/可运行"再次
  • 操作系统有另一个Y线程需要安排在CPU上执行。在选择线程并给定CPU周期之前需要Z ms。

似乎Android为后台应用程序中的线程提供了更低的优先级,导致在线程执行之前看起来像Z = 36ms的延迟。

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

答案 1 :(得分:-1)

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

  

因为运行服务的进程排名高于进程   与后台活动,一个启动长期运行的活动   相反,操作可能会为该操作启动服务   而不是简单地创建一个工作线程 - 特别是如果操作将   可能比活动更持久。例如,上传的活动   网站上的图片应该启动服务以执行上传   这样即使用户上传也可以在后台继续   离开活动。使用服务可以保证操作   将至少拥有"服务流程"优先,不管是什么   发生在活动中。

有关进程(服务,活动)和主题(及其优先级)here的更多信息。服务可以是后台和前台,更多地了解它们here(这可能会帮助你弄清楚你是否实现了错误,所以你可以解决它。)

至于您的具体问题,请尝试检查sleepTime值,可能存在一些问题(遗憾的是,我无法测试您的示例,但我会先检查该值),如果仍然不能找出问题所在,然后您应该尝试使用SystraceTraceview检查您的应用效果,并找出为什么在应用不可见时fps会降低...