2013-07-10 157 views
3

編輯:的Android了Thread.sleep有時等待的時間太長了

這不是在談論精度問題,從代碼和下面登錄,你可以看到,我要求睡1秒,但結果卻是幾乎200秒,有時它可以跳轉到600秒,這不可能是精確的問題..


我用handlerthread之前,有時張貼到剛剛處理程序作業不按時啓動,以獲得更多的細節我將其更改爲基本線程,結果發現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詠歎調,Android 2.2的 而外觀像它只在使用電池運行時發生,但我的應用程序在充電狀態上行爲不同。

+0

在Windows PC上我的問題,當您註釋掉'的getLocation()'它確實發生?看起來像另一個線程不會放棄CPU,一旦這個線程進入睡眠狀態。 – Aert

+0

@Aert,謝謝,我正在監視CPU使用情況,如果我發現了什麼,我會更新問題,謝謝。 – agou

+0

您是否在通過電源按鈕關閉Android顯示屏或顯示超時後執行此操作? –

回答

9

基本上Thread.sleep()Handlers只要屏幕開啓就會正常工作(意味着Android不應處於深度睡眠狀態/屏幕關閉狀態)。

當屏幕關閉時,Android的默認行爲是掛起Thread.sleep()和Handlers(),直到屏幕再次打開或者某個應用程序抓住喚醒鎖醒來。因此,如果屏幕始終處於打開狀態,那麼您的應用程序將完美工作,但當它關閉時,它將表現不正常。

最好的解決辦法是切換到AlarmManager,因爲當警報觸發時,默認情況下onRecieve()會捕獲喚醒鎖,導致Android喚醒並執行。

+0

謝謝。我有幾個問題:是否僅適用於由UI線程直接創建的線程,還是由Service/IntentService創建爲foreground的線程?這也適用於等待(超時)嗎?建議的AlarmManager是否必須點亮屏幕? (我需要每10秒運行一次操作。)您能提供鏈接到問題的文檔嗎?再次,非常感謝。 – GozzoMan

0

sleep() documentation警告說,這並不準確:

的精確度沒有保證 - 線程可以睡或多或少 比要求。

有一些相關的缺乏sleep()精度問題,比如this onethis one和幾個。谷歌爲「java線程睡眠精度」或「android線程睡眠精度」。

+0

感謝您的回覆,但這不是關於精確度,我要求睡1秒,結果是將近200秒,有時可能會跳到600秒,這不能是一個精確的問題... – agou

+0

我同意你的數字不同安靜一點,但API的描述絕對沒有任何承諾,特別是說'線程可能比請求多或少睡眠'的部分。如果你找到一個更有用的信息關於如何睡一個準確的金額,發佈作爲答案並接受它。這是公平的遊戲。 – chr

0

我也解決了這個問題,並不是說它不夠精確,而是等待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