我正在使用闹钟,但遇到了一个严重的问题,BroadCastReceiver 总是被及时准确地称为 ,我做了一些工作,例如获得意向额外费用,没什么大不了或很长,然后我将其称为警报活动。
里面有一个非常奇怪的行为,很多时候它都可以正常工作,但是有时候活动呼叫被延迟,而我在其中谈论的是 1-13分钟到目前为止我的测试,这对于警报应用程序是完全不能接受的。 当设备从打ze模式中醒来时,就会发生这种情况。
我正在使用setExactAndAllowWhileIdle()
,当呼叫接收方时,它的工作原理确实像是一种咒语,但从接收方开始的Activity却不是。
这是接收器代码的一部分:
@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分钟的延迟!
可以看到不到200毫秒后到达了“通话完成”Log.d。 可运行对象应该不成问题,因为在这种情况下它甚至还没有启动。 (如果一个正在运行,它只会等待以前运行的警报结束)
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分钟的警报,以确保系统肯定处于打ze模式(我不相信adb强制打ze模式):
前3个运行时goAsync
的运行时间非常完美。
第四次运行时,我又将代码改回了Thread,而没有明确地进行异步处理,这又延迟了4分钟以上。
使用postDelayed
和goAsync
进行的第五次测试又恰到好处。
我现在认为这可以可靠地工作,只要它不会再为时太晚。 万分感谢乔纳斯!!!我一直在为MONTHS争取这个问题,认为一个新的Thread就足够异步了;)
编辑2:
我现在已经对所有这些进行了1周的测试,但效果仍然不佳。 将可运行对象更改为:
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启动前台服务时,也会发生同样的事情。前台服务有时会在onCreate的中间停止,因为BR正在完成,并且设备似乎正在睡眠(变钝)...
我真的很绝望。
当我将BR中的第二个可运行时间分配给7.5而不是4.5秒时,我会注意到Google控制台中的ANR。 (尽管我相信那时的闹钟工作正常)。
解决此问题的正确方法是什么?正在启动asyncTask?
编辑3:
乔纳斯(Jonas),再次感谢您的回答-我整周尝试了许多不同的方法,在我的设备上,一切似乎都很好,但用户报告的延迟仍然高达13分钟...
我尝试过的2件事:
启动一个具有通知和唤醒锁的ForegroundService,作为AlarmReceiver中的唯一操作,并在服务中进行所有工作
卸下接收器并直接启动AlarmActivity以尽快完成所有工作-抓住唤醒锁并在活动中的第一件事上强制显示屏幕,然后获取IntentExtras并作为第三件事来启动音乐StreamService(全部)在1-2秒内)
第二种方法是我目前的状态,我认为它工作良好,直到有人再次报告延迟13分钟。
ForegroundService根本不起作用-它在音乐播放之前就经常入睡...我只允许该服务在音乐已经开始播放时结束,但是有时会在延迟之后发生-我不知道怎么办?这是不正确的,拥有唤醒锁的前台服务必须使设备保持唤醒状态!?!?
(我会发布活动,但其中包含750行,因此...不。)
无论如何:我还可以采取什么措施来使设备真正退出休眠模式?
setExactAndAllowWhileIdle 完美地工作
获取唤醒锁工作正常
获得IntentExtras 似乎运行良好
此后的某个时间,虽然我有唤醒锁并且屏幕被强制打开,但设备仍处于睡眠状态。
音乐服务已启动,但由于(我想)打do模式而无法完成缓冲
音乐播放在x分钟后开始
这就是我在日志中看到的内容,现在它可以在99%的时间内正常运行,但仍然很少发生。 我想念什么?有魔术功能可以使您停止x分钟的睡眠吗?
答案 0 :(得分:0)
现在,我认为可以通过重写启动过程并直接进入前景服务来解决此问题。
关于延迟:
我最近将setExactAndAllowWhileIdle
更改为setAlarmClock
,现在100%确定后一个在打ze模式下很晚(通常)-对于没有其他用例的用户可见的警报功能来说,它是一项好工作。
当我setExactAndAllowWhileIdle
在闹钟时间之前10秒,setAlarmClock
到“现在+ 10秒”时,甚至已经晚了。 (迟到1:55分钟。。。)
所以现在我回到setExactAndAllowWhileIdle
,它总是在时间上完美地调用BroadcastReceiver-总是!
我再次重写了整个启动过程(由于故障是非常随机的并且很少出现在我的测试设备上,所以经常进行更改)
第一种(旧的)长期有效的方法:
setExactAndAllowWhileIdle
-> BroadcastReceiver-> AlarmActivity-> StreamingService(前景)。
这运行了好几个月,但是突然之间我延迟了1到15分钟(我猜是在维护窗口),日志告诉我有时甚至前台服务确实启动了,音乐(ExoPlayer)开始缓冲,但是中断(我猜是打do睡),并在随机延迟时间后继续缓冲和播放。
在ForegroundService中足够奇怪了,不是吗?
我的新方法:
setExactAndAllowWhileIdle
-> BroadcastReceiver-> StreamService-> startActivity(AlarmActivity)->(startForeground(StreamService))->开始流音乐
在我两天的测试中以及在长时间的打do之后的早晨,这在3种不同的设备上都能正常工作。
BroadcastReceiver (在此处删除了所有异步内容)
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d("Ben", "AlarmReceiver HELLO");
Bundle b = intent.getExtras();
int intentId = 1909;
Intent alarmIntent = new Intent(context, StreamService.class);
if (b != null) {
alarmIntent.putExtras(b);
intentId = b.getInt("id");
Log.d("Ben", "AlarmReceiver found ID: " + intentId);
}
// CALC NEXT ALARM and start StreamingService...
if (Build.VERSION.SDK_INT >= 26) {
context.startForegroundService(alarmIntent);
context.startForegroundService(new Intent(context, CalcNextAlarmService.class));
Log.d("Ben", "SDK >= 26 *** context.startForegroundServices");
}
else {
context.startService(alarmIntent);
context.startService(new Intent(context, CalcNextAlarmService.class));
Log.d("Ben", "SDK < 26 *** context.startServices");
}
其他信息:
在服务中,我在onCreate()
中启动警报屏幕活动,然后在onStartCommand()
之后在startForeground()
中启动音乐流。
我现在将其视为我的工作解决方案,除非另行通知。 感谢您的帮助和建议,Jonas Lochmann!
编辑:警报再次延迟...我将开始一个新的干净帖子,内容涉及受打affected睡影响的前台服务...