BroadcastReceiver以随机延迟开始活动

时间:2018-06-24 19:41:12

标签: android broadcastreceiver delay start-activity

我正在使用闹钟,但遇到了一个严重的问题,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分钟以上。

使用postDelayedgoAsync进行的第五次测试又恰到好处。

我现在认为这可以可靠地工作,只要它不会再为时太晚。 万分感谢乔纳斯!!!我一直在为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行,因此...不。)

无论如何:我还可以采取什么措施来使设备真正退出休眠模式?

  1. setExactAndAllowWhileIdle 完美地工作

  2. 获取唤醒锁工作正常

  3. 获得IntentExtras 似乎运行良好

此后的某个时间,虽然我有唤醒锁并且屏幕被强制打开,但设备仍处于睡眠状态。

  1. 音乐服务已启动,但由于(我想)打do模式而无法完成缓冲

  2. 音乐播放在x分钟后开始

这就是我在日志中看到的内容,现在它可以在99%的时间内正常运行,但仍然很少发生。 我想念什么?有魔术功能可以使您停止x分钟的睡眠吗?

1 个答案:

答案 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睡影响的前台服务...