BroadcastReceiver 重新启动后接收事件有延迟

问题描述 投票:0回答:6

我尝试使用下一个 BroadcastReceiver 接收 PHONE_STATE 意图

<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 并拨打该设备后,在一分钟前通话结束后可以收到振铃事件。 我该如何修复它?有什么想法吗?

android broadcastreceiver
6个回答
2
投票

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

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

2
投票

根据此answer-中的CommonsWare

有很多很多应用程序想要在启动时获得控制权。如何 很快就会轮到你的,这取决于许多变量,例如 安装的应用程序数量、设备的 CPU 速度、数量 设备上的系统 RAM 等

此外,在启动时从 BroadcastReceiver 启动一个 Activity 是 相当邪恶。如果您想成为用户在访问后看到的第一件事 重新启动,编写主屏幕实现。

你能做的就是这样优先 -

 <action android:name="android.intent.action.BOOT_COMPLETED" android:priority="999"/>

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>

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;
}

0
投票

该值必须大于-1000且小于1000。请通过以下链接

http://developer.android.com/guide/topics/manifest/intent-filter-element.html


0
投票

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

假设:在启动时,通常有很多应用程序正在监听

BOOT_COMPLETED
(是的,这是一个不好的做法,但有些人仍然这样做,你应该责怪他们),因此后台队列非常繁忙。我并不奇怪在繁忙的队列中添加另一个后台广播需要一分钟才能处理

您可以通过在 logcat 中查找

来证实我的假设

ActivityManager:处理NextBroadcast

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

© www.soinside.com 2019 - 2024. All rights reserved.