2017-06-19 185 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类...

我希望这将帮助你......