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

时间:2017-01-12 15:44:13

标签: android broadcastreceiver

我尝试接收下一个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并拨打此设备后,可以在一分钟前完成呼叫后收到振铃事件。 我该如何解决?有什么想法吗?

6 个答案:

答案 0 :(得分:2)

根据此CommonsWare中的answer -

有许多应用程序希望在启动时获得控制权。你的转弯速度将取决于许多变量,例如安装的应用程序数量,设备的CPU速度,设备上的系统RAM数量等。

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

你所能做的就是优先考虑这个 -

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

答案 1 :(得分:1)

您可以使用前台服务并在前台服务中注册接收器而不是清单。使用前台服务可以减少延迟,因为前台服务比后台服务更重要,前台服务中的已注册接收器对于操作系统可能比清单中的已注册接收器更重要,因为您的程序始终在运行并且在电话状态更改之前处于前台。 / p>

此外我不认为ACTION_PHONE_STATE_CHANGED是有序广播,因为它不能被接收器中止,因此使用优先级,其他答案建议对它没有影响(优先级仅适用于有序广播)。

从清单中移除手机状态接收器,但将BOOT_COMPLETED接收器保留在清单中并在启动完成时开始关注服务

在服务的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;
}

答案 2 :(得分:0)

这是因为有任何其他接收器收听此广播,您可以尝试改善您的Recevier&#39;优先级就像那样

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

答案 3 :(得分:0)

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

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

答案 4 :(得分:0)

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

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

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

  

ActivityManager:processNextBroadcast

作为替代方案,您可以在register a listener

phone log content provider.

答案 5 :(得分:0)

我在想当你为发送广播创建Intent时,你会错过意图的set flag。您需要为您的意图设置标记 FLAG_RECEIVER_FOREGROUND

我没有看到源代码在本主题中创建了Intent来发送Broadcast,所以我建议一个示例:

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

您可以在https://codepen.io/JosephSilber/pen/vjKBRg

了解详情

修改

我刚刚更改了文件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>