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
毫秒,并且在每次迭代时检查是否应该进行帧捕获。
我正在尝试使用新的 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
毫秒,并且在每次迭代时检查是否应该进行帧捕获。