Android Thread.sleep有时等待太久了

时间:2013-07-10 02:09:01

标签: android multithreading

编辑:

这不是关于精度问题,从下面的代码和日志中,你可以看到我要求睡眠1秒,但结果差不多200秒,有时它可能会跳到600秒,这不可能是精度问题..


之前我正在使用handlerthread,有时发布到处理程序的作业没有按时启动,为了获得更多细节我将其更改为基本Thread,并且事实证明Thread.sleep()是问题,但我和#39;我不知道如何解决这个问题,原因可能是什么?

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()使用来自另一个线程的looper调用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 并且看起来像只有在使用电池运行时才会发生,但我的应用对充电状态的行为不同。

3 个答案:

答案 0 :(得分:9)

只要屏幕开启,基本上Thread.sleep()Handlers就可以正常工作(暗示Android不应处于深度睡眠状态/屏幕关闭状态)。

当屏幕关闭时,默认的Android行为是暂停Thread.sleep()和Handlers(),直到再次重新打开屏幕或某些应用程序抓住唤醒锁被唤醒。因此,如果屏幕全部打开,您的应用程序将完美运行,但是当它关​​闭时,它将表现不正常。

最好的解决方法是切换到AlarmManager因为触发闹钟时,onRecieve()默认会抓取唤醒锁,导致Android唤醒并执行。

答案 1 :(得分:0)

sleep() documentation警告说这不准确:

  

无法保证精度 - 线程可能会或多或少地睡眠   比要求。

有许多与sleep()精确度无关的问题,如this onethis one等等。谷歌为“java线程睡眠精度”或“android线程睡眠精度”。

答案 2 :(得分:0)

我也说出这个问题,而不是它不够精确,但是不是10秒,而是等待了30分钟 - 对于一个运行数周而且必须定期执行请求的应用程序,这不是解决方案。因此,我制作了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上。