3

编辑:

这里不是说精度问题,从下面的代码和日志中可以看出,我要求休眠1秒,结果几乎是200秒,有时会跳到600秒,这不可能是精度问题。 .


我之前使用过handlerthread,有时发布到handler的工作没有按时开始,为了获得更多详细信息,我将其更改为基本线程,结果发现Thread.sleep()是问题所在,但我不是确定如何解决这个问题,可能的原因是什么?

hGpsThread = new Thread(mGpsWorker);
hGpsThread.start();

private final Runnable mGpsWorker = new Runnable() {
    @Override
    public void run() {
        long lastGpsRequestTime = 0;
        l.Write("GPS thread started.");
        while (isRunning) {
            l.Write("GPS thread loop start.");
            try {
                long currentTimeMillis = System.currentTimeMillis();
                if (currentTimeMillis >= lastGpsRequestTime + gpsUpdateInterval) {
                    l.Write("Requesting location update");
                    gpslib.getLocation();
                    lastGpsRequestTime = currentTimeMillis;
                }
                l.Write("GPS thread before sleep");
                Thread.sleep(1000);
                l.Write("GPS thread after sleep");
            } catch (InterruptedException e) {
            }
            l.Write("GPS thread loop end.");
        }
        l.Write("GPS thread ended.");
    }
};

注意: getLocation() 使用来自另一个线程的循环器调用 requestLocationUpdates,因此据我所知,位置更新不应影响该线程。

getLocation() 还会创建一个 Timer 并安排一个超时,这可能是问题吗?据我了解,这应该不是问题。

这是日志:(这只是偶尔发生,说机会接近 0.5%)

Wed Jul 10 11:45:46 AEST 2013 GPS thread loop start.
Wed Jul 10 11:45:46 AEST 2013 GPS thread before sleep
Wed Jul 10 11:49:04 AEST 2013 GPS thread after sleep
Wed Jul 10 11:49:04 AEST 2013 GPS thread loop end.

谢谢

测试环境是:HTC Aria,Android 2.2看起来它只发生在使用电池运行时,但我的应用程序在充电状态下的行为并没有什么不同。

4

3 回答 3

9

基本上只要屏幕打开就可以正常工作(意味着Android不应该处于深度睡眠状态/屏幕关闭状态)Thread.sleep()Handlers

当屏幕关闭时,默认的 Android 行为是暂停 Thread.sleep() 和 Handlers() 直到屏幕再次打开或被某个应用程序获取唤醒锁唤醒。因此,如果屏幕始终处于打开状态,您的应用程序将完美运行,但当它关闭时,它的行为将变得异常。

最好的解决方法是切换到,AlarmManager因为当触发警报时onRecieve(),默认情况下总是抓取一个唤醒锁,导致 Android 唤醒并执行。

于 2013-07-10T08:19:56.017 回答
0

sleep()文档警告说它不准确:

不能保证精度 - 线程可能比请求的睡眠时间更多或更少。

有许多与 缺乏精确性有关的问题sleep(),例如this onethis one和其他一些。谷歌“java线程睡眠精度”或“android线程睡眠精度”。

于 2013-07-10T02:26:40.477 回答
-1

我也讨厌这个问题,并不是说它不够精确,而是线程等待了 30 分钟而不是 10 秒——对于一个运行数周且必须定期执行请求的应用程序,这不是解决方案。因此,我制作了 BetterSleeper :-)

import java.sql.Timestamp;

public class BetterSleeper {

    public static void sleepSeconds(int seconds_to_wait) {
        System.out.println("START WAIT FOR "+seconds_to_wait+" SECONDS");
        BetterSleeper.sleepMillis(seconds_to_wait*1000);
        System.out.println("END WAIT");
    }

    public static void sleepMillis(int milliseconds_to_wait) {
        System.out.println("START WAIT FOR "+milliseconds_to_wait+" MILLISECONDS");
        Timestamp timestamp = new Timestamp(System.currentTimeMillis());
        long start_milliseconds = timestamp.getTime();
        long end_milliseconds = start_milliseconds + milliseconds_to_wait;
        while (true) {
            Timestamp endtime = new Timestamp(System.currentTimeMillis());
            if ((endtime.getTime()) >= end_milliseconds) {
                break;
            }
        }
        System.out.println("END WAIT");
    }
}

如果您考虑到此代码段中的处理时间实际上几乎没有影响,那么这实际上被证明要准确得多,因为它会被记住它何时开始以及何时应该在开始时停止。

另一个优点是您没有分派睡眠线程的所有缺点,例如 Thread.sleep,如果您终止主线程,后台线程将被放弃。


注意我与 Android 开发无关 - 我的问题发生在运行 Windows 10 的 Windows PC 上。

于 2017-07-14T07:01:21.357 回答