广播接收器在重启后延迟接收事件。

8

我尝试使用下一个广播接收器来接收“电话状态”意图。

<receiver android:name=".CallReceiver"
    android:enabled="true"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.PHONE_STATE" />
        <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
</receiver>

但是在重启我的Nexus 5X并拨打给此设备的电话后,铃声事件可以在通话结束一分钟之后收到。

我该怎么解决?有什么想法吗?


在intent-filter中使用优先级,例如:<intent-filter android:priority="999">,并查看下面的链接以获取更多详细信息。https://developer.android.com/guide/topics/manifest/intent-filter-element.html#priority - Dhaval Parmar
你在使用哪个API级别? - rds
你如何注册广播接收器?只能隐式地吗? - rds
@rds API = 26,仅隐式。 - shmakova
6个回答

2
根据CommonsWare在这个答案中所述- 很多应用程序希望在启动时获得控制权。您的应用程序何时获得控制权取决于许多变量,例如已安装应用程序的数量、设备的CPU速度、设备上的系统RAM数量等。
此外,在启动接收器(BroadcastReceiver)中启动活动是相当不好的。如果您想成为用户重新启动后看到的第一件事,请编写主屏幕实现。
你可以像这样给出优先级 -
 <action android:name="android.intent.action.BOOT_COMPLETED" android:priority="999"/>

优先级是有序广播,我认为 boot_completed 不是有序广播。 - ygngy
android:priority是在<receiver(用于广播接收器)下的<intent-filter>标签中。 - ralphgabb

2

这是因为有其他接收器在监听此广播,你可以尝试提高你的接收器优先级,就像这样。

<intent-filter android:priority="2147483647">  
<action android:name="android.intent.action.BOOT_COMPLETED" />  
</intent-filter>

1

我想当你创建发送广播的意图时,你忘了为意图设置标志。你需要为你的意图设置标记FLAG_RECEIVER_FOREGROUND

我在这个主题中没有看到创建发送广播意图的源代码,所以我建议提供一个示例:

Intent intent = new Intent();
intent.setAction(...);
intent.setFlags(FLAG_RECEIVER_FOREGROUND);
...

您可以在此处查看更多内容:https://developer.android.com/reference/android/content/Intent.html#FLAG_RECEIVER_FOREGROUND

编辑:

我刚刚更改了AndroidManifest文件,您可以尝试一下:

<receiver android:name=".CallReceiver"
            android:enabled="true"
            android:exported="true"
            android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
            <intent-filter>
                <action android:name="android.intent.action.PHONE_STATE" />
                <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>

我没有发送任何广播,我只是收到了它。 - shmakova
@shmakova:我刚刚更新了答案,你可以再试一次。 - chaunv
问题出在PHONE_STATE广播上,RECEIVE_BOOT_COMPLETED正常工作。 - shmakova

1
你可以使用前台服务并在前台服务中注册接收器,而不是在清单文件中注册。使用前台服务可能会减少延迟,因为前台服务比后台服务更重要,并且在前台服务中注册的接收器可能比在清单文件中注册的接收器更重要,因为您的程序始终在前台运行并在电话状态更改之前处于活动状态。
另外,我认为ACTION_PHONE_STATE_CHANGED不是有序广播,因为它不能被接收器中止,因此使用其他答案建议的优先级对其没有影响(优先级仅适用于有序广播)。
从清单文件中删除电话状态接收器,但保留BOOT_COMPLETED接收器,并在启动完成后启动以下服务。
在Service的onCreate中注册接收器。
   @Override
    public void onCreate() {
        super.onCreate();
        phoneStateReceiver = new PhoneStateReceiver();
        registerReceiver(phoneStateReceiver, new IntentFilter(TelephonyManager.ACTION_PHONE_STATE_CHANGED));
    }

在onDestroy中取消注册:
   @Override
    public void onDestroy() {
        unregisterReceiver(phoneStateReceiver);
        super.onDestroy();
    }

向您的服务添加一个静态方法以启动服务:

// start service even if your app is in stopped condition in android 8+
static void requestStart(@NonNull final Context context, @NonNull final String action){
        final Context appContext = context.getApplicationContext();
        Intent intent = new Intent(appContext, AppService.class);
        intent.setAction(action);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            // this is required to start the service if there is 
            // no foreground process in your app and your app is
            // stopped in android 8 or above
            appContext.startForegroundService(intent);
        } else {
            appContext.startService(intent);
        }
    }

在你的onStartCommand中启动前台。
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
         if(ACTION_START.equals(intent.getAction()))
           startForeground(ID, notification);
         else if(ACTION_STOP.equals(intent.getAction()))
           stopForeground(true);

         return START_STICKY;
}

如在此处所提到的:https://issuetracker.google.com/37273064#comment4,ACTION_PHONE_STATE_CHANGED(android.intent.action.PHONE_STATE)将被列入Android O版本的白名单。尽管它们可能会在未来的版本中用不同的机制替代。 - shmakova
问题是关于重启后的延迟,而不是为什么它在Android O上无法工作。 - shmakova
@shmakova,它还可能解决延迟问题,因为您的服务处于前台并且对操作系统比后台服务甚至已停止的应用状态更重要。 - ygngy
@shmakova 我认为PHONE_STATE不是有序广播,因为它无法被中止,因此使用其他答案建议没有效果的“优先级”。 - ygngy
@shmakova,设置意图中的标志位并没有意义,因为发送电话状态的意图不是你发送的,而是电话应用程序通知你电话状态,并且你只是接收该意图。 - ygngy
更改您的答案并在那里写有关有序广播的内容。 - shmakova

0

0

ACTION_PHONE_STATE_CHANGED没有FLAG_RECEIVER_FOREGROUND标志,因此它在后台队列中运行。

假设:在启动时,通常有许多应用程序正在监听BOOT_COMPLETED(是的,这是一种不好的做法,但仍然有人这样做,你应该责备他们),因此后台队列非常繁忙。我不惊讶另一个添加到繁忙队列中的后台广播需要一分钟才能处理。

您可以通过查看logcat来确认我的假设

ActivityManager: processNextBroadcast

作为替代方案,您可以注册侦听器电话日志内容提供程序上。


它怎么可能需要一分钟才能广播呢?Nexus 5X 配置不错,最多只需要10秒钟。你能详细解释一下或提供任何链接吗?谢谢! - Jitesh Mohite
你在logcat中观察到了哪些时间戳? - rds

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接