【发布时间】:2018-12-03 10:23:35
【问题描述】:
我正在制作闹钟,但我遇到了一个严重的问题,BroadCastReceiver总是被准确地及时调用,我做了一些工作,比如获取额外的意图,不重也不长,然后我调用警报活动。
那里有非常奇怪的行为,很多时候它都可以正常工作,但有时活动调用会延迟,我说的是1-13分钟到目前为止,我的测试对于警报应用程序来说是完全不可接受的。 当设备从打盹模式唤醒时会发生这种情况。
我正在使用setExactAndAllowWhileIdle(),它在调用接收器时确实很有魅力,但从接收器开始的活动却没有。
这是接收方代码的一部分:
@Override
public void onReceive(Context context, Intent intent) {
Log.d("Ben", "Alarmreceiver HELLO");
[...]
Log.d("Ben", "Alarmreceiver CALLING WAKE SCREEN NOW");
if (wait) {
new Thread(new Runnable() {
@Override
public void run() {
Log.d("Ben", "AlarmReceiver: Alarm still running, wait for finsihing...");
try {
Thread.sleep(3_000);
} catch (Exception e) {
context.startActivity(new Intent("package.action.alarm").addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
context.startActivity(new Intent("package.action.alarm").addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
}).start();
}
else
context.startActivity(new Intent("package.action.alarm").addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
Log.d("Ben", "Call done.");
}
//end of receiver
这是我从 LogCat 得到的:
06-24 20:50:02.623 6527-6527/package D/Ben: Alarmreceiver HELLO
06-24 20:50:02.753 6527-6527/package D/Ben: Alarmreceiver CALLING WAKE SCREEN NOW
06-24 20:50:02.794 6527-6527/package D/Ben: Call done.
06-24 20:55:09.129 6527-6527/package D/Ben: AlarmActivity.onCreate()
如您所见,命令和实际活动开始之间有 5 分钟的延迟!
可以看到“调用完成”Log.d 在不到 200 毫秒后到达。 runnable 应该不是问题,因为在这种情况下它甚至还没有启动。 (如果一个正在运行,它只会等待先前运行的警报结束)
AlarmActivity.onCreate() 的 Log.d 是 AlarmActivity 中的第一条语句,紧接着我获得了唤醒锁。
我试过了:intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);,因为我在另一篇文章中找到了它,但行为完全没有变化。
这真是令人沮丧 - 有谁知道为什么会发生这种情况或我该如何解决?
编辑
现在我用以下代码交换了新线程:
final PendingResult result = goAsync();
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
context.startActivity(new Intent("package.action.alarm").addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
Log.d("Ben", "Runnable done.");
result.finish();
}
}, 2_000);
一切似乎工作正常。 我今天进行了 5 次长期测试,每次都设置了 +50 或 60 分钟的警报,以确保系统确实处于打盹模式(我不相信 adb force doze 模式):
goAsync 的前 3 次运行非常及时。
第四次运行,我将代码改回线程而没有明确地异步,再次迟到了 4 分钟以上。
postDelayed 和goAsync 的第五次测试再次完美地进行了。
我现在认为这可以可靠地工作,只要它不会再次响起为时已晚。 千感谢乔纳斯!我几个月来一直在与这个问题作斗争,认为一个新的线程就足够异步了;)
编辑 2:
我现在已经对所有这些进行了 1 周的测试,但它仍然不能很好地工作。 在我将 runnable 更改为:
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
context.startActivity(new Intent("package.action.alarm").addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
Log.d("Ben", "Activity has been called.");
// give an extra 4.5 sec window to start activity and alarm stream...
Handler h = new Handler();
h.postDelayed(new Runnable() {
@Override
public void run() {
result.finish();
Log.d("Ben", "Allowing Rec. finish now...");
}
}, 4_500);
}
}, 2_000);
它工作正常,但不是 100%。 (2 秒是完成一个已经在运行的警报,而 4.5 秒我希望给 Activity 和 Service 足够的时间来启动流,然后它会正常工作)
附加信息:
接收器正在启动一个活动,第一个动作是获取唤醒锁(wifi 和电源)并强制屏幕打开。 之后我进行电话处理,然后我启动一个前台服务,它将播放音乐。
我到处都有 Log.d 并且可以看到,有时,当流缓冲时间过长 - 以至于 BR 中的 4.5 秒已经过去时,设备进入睡眠状态并且直到随机播放音乐才开始播放时间又过去了(我猜是维护窗口)即使已经获得了唤醒锁。
这与 Runnable 无关,我现在发现了。我删除了它并在 BR 结束时直接调用了 Activity,导致在 Activity 启动过程中几乎肯定会延迟几分钟。无需异步 - 它会更快地入睡...
当 BR 完成时,我应该如何从广播接收器开始一个没有睡着/打瞌睡的 Activity?
这对我来说似乎是一个错误。或者我错过了一些非常基本的东西。 屏幕一直亮着,但有时会在该延迟(几分钟)之后启动前台流媒体服务。
当我从 BR 启动前台服务时,也会发生同样的事情。前台服务有时会在 onCreate 中间停止,因为 BR 正在完成并且设备似乎处于睡眠状态(打瞌睡)......
我真的很绝望。
当我给 BR 中的第二个可运行文件 7.5 而不是 4.5 秒时,我可以注意到 Google 控制台中的 ANR。 (虽然我相信警报当时工作得很好)。
解决这个问题的正确方法是什么?启动 asyncTask?
编辑 3:
乔纳斯,再次感谢您的回答 - 我整周尝试了很多不同的方法,在我的设备上一切似乎都很好,但用户报告延迟最多 13 分钟...
我尝试了 2 件事:
使用通知和唤醒锁启动 ForegroundService 作为 AlarmReceiver 中的唯一操作,并在服务内完成所有工作
移除接收器并直接启动 AlarmActivity 以尽快完成所有工作 - 获取唤醒锁并强制屏幕作为活动中的第一件事,然后获取 IntentExtras 并启动音乐 StreamService 作为第三件事(所有1-2 秒内)
第二种方法是我目前的状态,我认为它运行良好,直到有人再次报告延迟 13 分钟。
ForegroundService 根本不起作用 - 它经常在音乐播放之前就睡着了......我只允许这个服务在音乐已经开始播放时结束,但这有时会在延迟之后发生 - 我不知道是怎么回事?这不可能是正确的,带有唤醒锁的foregroundService 必须保持设备唤醒!?!?
(我会发布活动,但它由 750 行组成,所以......不。)
无论如何:我还能做些什么来真正保持/强制设备退出打盹模式?
setExactAndAllowWhileIdle 完美运行
获取唤醒锁工作正常
获得 IntentExtras 似乎效果不错
之后设备进入睡眠状态,虽然我得到了唤醒锁并且屏幕被强制打开。
音乐服务已启动,但由于(我猜)再次打盹模式而未完成缓冲
音乐在 x 分钟后开始播放
这就是我在日志中看到的,现在它在 99% 的情况下都能正常运行,但很少会发生。 我错过了什么?有什么神奇的功能可以让x分钟停止打瞌睡吗?
【问题讨论】:
-
如果另一个警报仍在运行(该时间用于在再次启动警报服务之前停止警报服务),我想以 3 秒的延迟启动活动。但在这种情况下,线程没有启动。该活动在 ELSE 中调用,应立即启动。似乎系统再次进入睡眠状态,实际上在打盹模式的下一个维护窗口中开始了活动(我相信这是随机延迟时间)。
标签: android broadcastreceiver delay start-activity