2017-06-19 187 views
7

我有一個應用程序,它使用AlarmManager每X時間安排一個重複報警。當我的接收器收到Intent時,它必須發出http請求。網絡呼叫報警超時

鬧鐘本身工作正常,並在應該時觸發。但是,網絡電話在手機未使用時開始超時。更具體地說:

當我安排每分鐘開火(壞習慣,我知道,但只是爲了說明),請求成功的第一個5-8分鐘。之後,我得到java.net.SocketTimeoutException: connect timed out。有時它確實成功,但大多數情況是這樣。

我試圖設置連接/讀/寫超時到一分鐘,但後來我得到這個異常,而不是上面的那個:java.net.ConnectException: Failed to connect to myapp.example.com/123.45.67.89:80

我的代碼:

public class AlarmReceiver extends BroadcastReceiver { 

    @Override 
    public void onReceive(Context context, Intent intent) { 
     // Consider mApi and myBody to be initialised and valid 
     mApi.myPostRequest(myBody).enqueue(new Callback<Void> { 

      @Override 
      public void onResponse(Call<Void> call, Response<Void> response) { 
       //Does not get here 
      } 

      @Override 
      public void onFailure(Call<Void> call, Throwable t) { 
       t.printStackTrace(); 
      } 
     } 
    } 
} 

事情我已經嘗試:

  • 如前所述,增加超時
  • 獲取在 onReceiveWakeLock和釋放它當調用完成(增加了 權限)

其他信息:

  • 報警使用 alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), interval, pendingIntent);從我 Activity設置。
  • 我使用的是改造(2.1.0)網絡通信,但你很可能已經猜到了,從我的代碼;)

如何讓網絡通話時,手機工作的任何想法睡眠?

+5

聽起來[打盹模式干擾(HTTPS: //developer.android.com/training/monitoring-device-state/doze-standby.html)。對於Android 5.0及更高版本的設備,請考慮切換到「JobScheduler」並將作業配置爲僅在有Internet連接時才能獲取控件。 – CommonsWare

回答

1

你在你的代碼中的錯誤基礎 - 你不能讓你的廣播接收器的請求(或任何長時間運行的操作) - 這後死亡〜10秒,這樣可能對你的一些失敗的原因。

您應該將請求邏輯移動到一個服務(IntentService),您將從廣播接收器開始並在那裏發出請求。

這應該工作得很好。

1

這裏,應該使用JobService,它有很多的約束來處理不同的情況,也是你的工作是保證由系統執行。

這裏的問題是打盹模式,使用JobService可以很容易地解決這個問題。

實現也很容易,所有你需要做的就是創建一個JobService和裏面的onStartJob()開始你的網線,然後就派遣你的工作。

更多細節

https://developer.android.com/reference/android/app/job/JobService.html

0

你應該使用AlarmManager.RTC_WAKEUP,不AlarmManager.ELAPSED_REALTIME_WAKEUP喚醒設備,你應該使用服務做你的工作開始在收到onReceivestartWakefulService(context, service.class)。這將確保設備完全喚醒,並在沒有超時的情況下進行網絡呼叫。

alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, SystemClock.elapsedRealtime(), interval, pendingIntent); 
2

https://developer.android.com/reference/android/content/BroadcastReceiver.html

一般來說,廣播接收器允許多達10 秒運行他們的系統之前,會考慮他們非響應性和ANR 應用。由於這些通常在應用程序的主線程上執行,因此它們已經受到可能發生的各種操作(更不用說僅僅是避免UI分叉)的約5秒的時間限制,所以 接收限制通常不受關注。但是,一旦您使用 {@goAsync},雖然可以關閉主線程,但廣播 執行限制仍然適用,包括調用此方法和最終PendingResult.finish()之間花費的時間 。

延伸閱讀說

如果你正在服用這種方法的優點有更多的時間來執行 ,它是有用的知道可用的時間可以更長 某些情況下。特別是,如果您收到的廣播 不是前臺廣播(也就是說,發件人未使用 FLAG_RECEIVER_FOREGROUND),則允許接收器 運行的時間更長,允許它們執行30秒甚至更長的時間多一點。

(長工作要踢到另一個系統設施如 JobSchedulerService,或看到特別JobIntentService),

您可以嘗試使用@goAsync。或者你可以切換你的邏輯JobIntentService

我還沒有測試任何這些。

1

從顯影劑文檔:https://developer.android.com/reference/android/app/AlarmManager.html

警報管理器,只要該報警 接收機的onReceive()方法被執行保持CPU喚醒鎖。這可保證在處理完廣播之前,手機將不會睡眠。 一旦onReceive()返回,警報管理器將釋放此喚醒鎖。 這意味着手機會在某些情況下,只要你的 的onReceive()方法睡眠完成

在你的代碼的onReceive將返回之前將被執行mApi.myPostRequest(myBody).enqueue ...任務,那麼這個任務可能會被永遠不會到期的執行CPU將在onReceive返回時立即停止。

你說你測試獲取激活鎖定,但新的Android 6.0打盹模式忽略wakelocks

看來的onReceive將不得不等待任務結束

一些想法:

檢查一些在thread.sleep循環終止標誌?

如果任務使用Thread對象,然後使用thread.join()?

0

如果問題是由打盹和Wakelocks造成被忽略,你應該嘗試在https://developer.android.com/training/monitoring-device-state/doze-standby.html提供的提示:

標準AlarmManager報警(包括setExact()和setWindow())是>推遲到下一個維護窗口。

  • 如果您需要設置報警火災而在打盹,使用setAndAllowWhileIdle()>或setExactAndAllowWhileIdle()。
  • 用setAlarmClock()設置的警報繼續正常激活 - 系統在這些警報激發之前不久就打瞌睡。
0

有你實現2個問題:

1)如果廣播接收機不拿完10秒內執行,然後ANR會發生。 2)所有的網絡通話都在後臺進行了優化,所以當設備被喚醒時它可能會工作,否則不會觸發HTTP請求來節省電池和其他資源。

你應該做的是在服務內部創建一個循環(休眠時間爲幾秒),檢查每次迭代的時間以及何時達到該時間然後執行任務,當嘗試將文件上傳到服務器在1小時的間隔,所以我決定在我自己的工作,而不是使用AlarmManager類...

我希望這將幫助你......