2017-06-19 52 views
7

Tôi có một ứng dụng sử dụng AlarmManager để lên lịch báo thức lặp lại sau mỗi khoảng thời gian X. Khi người nhận của tôi nhận được Intent, nó phải thực hiện một yêu cầu http.Cuộc gọi mạng vào thời gian báo thức ra

Báo thức hoạt động tốt và kích hoạt khi cần. Cuộc gọi mạng, tuy nhiên, bắt đầu định thời gian khi điện thoại không được sử dụng. Để cụ thể hơn:

Khi tôi lên lịch để kích hoạt từng phút (thực hành không tốt, tôi biết, nhưng chỉ để minh họa), 5-8 phút đầu tiên yêu cầu thành công. Sau đó, tôi nhận được java.net.SocketTimeoutException: connect timed out. Đôi khi nó thành công, nhưng chủ yếu là điều này xảy ra.

Tôi đã thử đặt thời gian chờ kết nối/đọc/ghi trong một phút, nhưng sau đó tôi nhận ngoại lệ này thay vì một ngoại lệ: java.net.ConnectException: Failed to connect to myapp.example.com/123.45.67.89:80.

Mã của tôi:

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(); 
      } 
     } 
    } 
} 

Những điều tôi đã cố gắng:

  • như đã nêu trước đó, timeouts tăng
  • mua một WakeLock trong onReceive và phát hành nó khi cuộc gọi được thực hiện (đã thêm sự cho phép )

thông tin khác:

  • Các báo động được thiết lập sử dụng alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), interval, pendingIntent); từ tôi Activity.
  • Tôi đang sử dụng Retrofit (2.1.0) cho mạng lưới giao thông, nhưng có thể bạn có thể đoán rằng từ mã của tôi;)

Bất kỳ ý tưởng về cách để có được những cuộc gọi mạng làm việc khi điện thoại ngủ?

+5

Âm thanh như [Nữu Thừa chế độ can thiệp] (https: //developer.android.com/training/monitoring-device-state/doze-standby.html). Đối với thiết bị Android 5.0+ của bạn, hãy cân nhắc chuyển sang 'JobScheduler' và định cấu hình các công việc để chỉ kiểm soát khi có kết nối Internet. – CommonsWare

Trả lời

1

Bạn có lỗi cơ bản trong mã của mình - bạn không thể thực hiện yêu cầu (hoặc bất kỳ hoạt động chạy dài nào) trong bộ thu phát của bạn - nó mất sau ~ 10 giây để có thể là lý do cho một số lỗi của bạn.

Bạn nên di chuyển logic yêu cầu đến dịch vụ (IntentService) mà bạn sẽ bắt đầu từ bộ thu phát sóng của mình và thực hiện yêu cầu ở đó.

Điều đó sẽ hoạt động tốt.

1

Bạn nên sử dụng JobService ở đây, nó có nhiều ràng buộc để xử lý các tình huống khác nhau và công việc của bạn cũng được đảm bảo sẽ được hệ thống thực thi.

Sự cố ở đây là chế độ ngủ gật và việc sử dụng JobService có thể được giải quyết dễ dàng.

Thực hiện cũng dễ dàng tất cả những gì bạn cần làm là tạo một JobService và bên trong nó là onStartJob() bắt đầu chuỗi mạng của bạn và sau đó chỉ gửi công việc của bạn.

Để cụ thể hơn

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

0

Bạn nên sử dụng AlarmManager.RTC_WAKEUP, không AlarmManager.ELAPSED_REALTIME_WAKEUP thức dậy thiết bị và bạn nên sử dụng một dịch vụ để làm công việc của bạn bắt đầu trong nhận trong onReceive với startWakefulService(context, service.class). Điều này sẽ đảm bảo rằng thiết bị sẽ hoàn toàn thức dậy và thực hiện cuộc gọi mạng mà không có thời gian chờ.

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

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

Theo nguyên tắc chung, thu phát sóng được phép chạy lên đến 10 giây trước khi hệ thống sẽ xem xét họ không đáp ứng và ANR ứng dụng. Vì các lệnh này thường được thực hiện trên luồng chính của ứng dụng, chúng đã bị giới hạn bởi giới hạn thời gian ~ 5 giây của các hoạt động khác nhau có thể xảy ra ở đó (chưa kể chỉ tránh giao diện người dùng), vì vậy giới hạn nhận thường không phải là mối quan tâm . Tuy nhiên, khi bạn sử dụng {@goAsync}, mặc dù có thể tắt chủ đề chính, giới hạn thực hiện phát sóng vẫn áp dụng và bao gồm thời gian dành giữa việc gọi phương thức này và cuối cùng là PendingResult.finish().

Đọc thêm nói

Nếu bạn đang lợi dụng phương pháp này để có thêm thời gian để thực hiện , nó rất hữu ích để biết rằng thời gian có sẵn có thể được kéo dài trong tình huống nhất định. Cụ thể, nếu chương trình phát sóng bạn nhận được không phải là phát sóng nền trước (nghĩa là người gửi không sử dụng FLAG_RECEIVER_FOREGROUND), thì sẽ có thêm thời gian cho người nhận chạy, cho phép họ thực hiện trong 30 giây hoặc thậm chí một chút nữa.

(làm việc lâu nên punted khác cơ sở hệ thống như JobScheduler, Service, hoặc xem đặc biệt là JobIntentService),

Bạn có thể thử sử dụng @goAsync. Hoặc bạn có thể chuyển đổi logic của mình thành JobIntentService

Tôi chưa thử nghiệm bất kỳ điều nào trong số này.

1

Từ tài liệu phát triển: https://developer.android.com/reference/android/app/AlarmManager.html

Alarm Giám đốc tổ chức một khóa trỗi dậy CPU chừng phương pháp báo động nhận của onReceive() được thực hiện. Điều này đảm bảo rằng điện thoại sẽ không ngủ cho đến khi bạn xử lý xong chương trình phát sóng. Khi onReceive() trả về, Trình quản lý báo thức sẽ giải phóng khóa chế độ thức tỉnh này. Điều này có nghĩa rằng điện thoại sẽ trong một số trường hợp ngủ càng sớm càng phương pháp onReceive() của bạn hoàn

Trong mã của bạn onReceive sẽ trở lại trước khi mApi.myPostRequest(myBody).enqueue ... nhiệm vụ sẽ được thực hiện, sau đó nhiệm vụ này có thể sẽ được bao giờ thực hiện do các CPU sẽ dừng ngay sau khi nhận được trả về.

Bạn nói bạn đã thử nghiệm có được một WakeLock, nhưng Android chế độ 6.0 Nữu Thừa mới bỏ qua wakelocks

Dường như OnReceive sẽ phải đợi cho nhiệm vụ chấm dứt

Một số ý tưởng:

Kiểm tra một số chấm dứt cờ trong một vòng lặp với thread.sleep?

Nếu tác vụ sử dụng đối tượng Thread sau đó sử dụng thread.join()?

0

Nếu vấn đề là do Nữu Thừa và Wakelocks bị bỏ qua, bạn nên thử những lời khuyên được cung cấp trong https://developer.android.com/training/monitoring-device-state/doze-standby.html:

Chuẩn AlarmManager báo động (bao gồm cả setExact() và setWindow()) là> hoãn lại đến tiếp theo cửa sổ bảo trì.

  • Nếu bạn cần đặt báo thức kích hoạt trong khi ở Doze, hãy sử dụng setAndAllowWhileIdle()> hoặc setExactAndAllowWhileIdle().
  • Báo thức được đặt bằng setAlarmClock() tiếp tục kích hoạt bình thường - hệ thống thoát Doze ngay trước khi báo thức đó kích hoạt.
0

có 2 vấn đề trong việc thực hiện của bạn:

1) nếu thu phát sóng không được thực hiện trong vòng 10 giây xong rồi ANR sẽ xảy ra. 2) Tất cả các cuộc gọi mạng được tối ưu hóa ở chế độ nền, vì vậy khi thiết bị đang hoạt động, thiết bị có thể hoạt động khác sẽ không kích hoạt yêu cầu HTTP để tiết kiệm pin và các tài nguyên khác.

những gì bạn cần làm là dịch vụ bên trong tạo vòng lặp (với thời gian ngủ vài giây) để kiểm tra thời gian trên mỗi lần lặp lại và thời gian đó đạt được sau đó thực hiện tác vụ, tôi cũng phải đối mặt với các vấn đề đó khi cố tải tệp lên máy chủ tại một khoảng thời gian là 1 giờ, vì vậy tôi đã quyết định làm việc một mình hơn là sử dụng lớp AlarmManager ...

tôi hy vọng điều này sẽ giúp bạn ...

Các vấn đề liên quan