后台执行不允许接收意图BOOT_COMPLETED

时间:2018-04-26 10:26:00

标签: android broadcastreceiver android-8.0-oreo android-background

我已经阅读了有关Android Oreo后台执行限制的内容,并且明确指出BOOT_COMPLETED广播未受影响,但我无法在Android Oreo上运行。

首先,我正在编译SDK 27.其次,我在清单文件中声明了接收器:

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    <receiver
        android:name="helpers.StartDetectionAtBoot"
        android:label="StartDetectionAtBoot"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <category android:name="android.intent.category.DEFAULT"/>

            <action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>

            <action android:name="android.intent.action.BOOT_COMPLETED"/>
            <action android:name="android.intent.action.QUICKBOOT_POWERON"/>
            <!--For HTC devices-->
            <action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
            <!--For MIUI devices-->
            <action android:name="android.intent.action.REBOOT"/>
        </intent-filter>
    </receiver>

然后是接收器的实现,它也可以很简单:

public class StartDetectionAtBoot extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i("test", "test");

        Intent intent0 = new Intent( context, ActivityRecognitionService.class );
        PendingIntent pendingIntent = PendingIntent.getService(context, 111, intent0, PendingIntent.FLAG_UPDATE_CURRENT);
        ActivityRecognitionClient activityRecognitionClient = ActivityRecognition.getClient(context);
        activityRecognitionClient.requestActivityUpdates(5000, pendingIntent);
    }
}
未调用

onReceive方法,我将始终在Android Oreo设备/模拟器上收到logcat错误:

  

W / BroadcastQueue:不允许后台执行:接收Intent {   act = android.intent.action.BOOT_COMPLETED flg = 0x400010}

阅读其他答案,他们说在清单中注册显式意图时存在一些问题,但BOOT_COMPLETED不是这种情况。

this都没有帮助,因为根本没有调用接收器。

在运行时注册广播意图,让它工作(在模拟器上,从adb shell发出意图),但我不确定它是正确的方法:

registerReceiver(new StartDetectionAtBoot(), new IntentFilter(Intent.ACTION_BOOT_COMPLETED));

是否有任何已知的错误?

3 个答案:

答案 0 :(得分:1)

针对所需的隐式意图在代码中自我注册接收者实际上是开始接收该意图的正确方法。不需要任何服务(在大多数情况下,请参阅下文...)。 但是您需要注意以下几点,以免在测试过程中产生混淆并且不会破坏早期的实现:

  1. 自注册应该在每个应用程序运行时执行一次。就Java / Kotlin应用程序数据而言:每静态字段寿命一次。因此,一个静态布尔值字段应该让您知道:是否需要自我注册(例如,在重新启动后或Android系统稍后杀死您的应用之后...)(我引用此提交的工作代码:https://github.com/andstatus/todoagenda/commit/74ffc1495f2c4bebe5c43aab13389ea0ea821fde ):
    private static volatile boolean receiversRegistered = false;

    private static void registerReceivers(Context contextIn) {
        if (receiversRegistered) return;

        Context context = contextIn.getApplicationContext();
        EnvironmentChangedReceiver receiver = new EnvironmentChangedReceiver();

        IntentFilter providerChanged = new IntentFilter();
        providerChanged.addAction("android.intent.action.PROVIDER_CHANGED");
        providerChanged.addDataScheme("content");
        providerChanged.addDataAuthority("com.android.calendar", null);
        context.registerReceiver(receiver, providerChanged);

        IntentFilter userPresent = new IntentFilter();
        userPresent.addAction("android.intent.action.USER_PRESENT");
        context.registerReceiver(receiver, userPresent);

        Log.i(EventAppWidgetProvider.class.getName(), "Registered receivers from " + contextIn.getClass().getName());
        receiversRegistered = true;
    }
  1. 将对您的registerReceivers方法的调用插入到应用程序的所有所有可能的入口点,以最大程度地增加接收器被注册的机会,即使您的应用程序仅由Android系统启动一次,例如: / li>
    @Override
    public void onUpdate(Context baseContext, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        registerReceivers(baseContext);

        ...
    }
  1. 您可以在AndroidManifest.xml文件中将接收者注册为相同的意图(因为这在v.7之前适用于Android ...),但请注意,在这种情况下,在logcat中您仍然会看到“不允许后台执行”,并参考您的接收者。这仅意味着无法通过AndroidManifest.xml进行注册(正如Android 8+所预期的那样),但是无论如何都应该调用自注册接收者!

  2. 如上所述,light窗口小部件通常不需要启动前台服务。而且,用户将不希望不断看到有关您的“小部件”正在前台运行的通知(因此会不断消耗资源)。唯一确实需要这样做的情况是,Android过于频繁地杀死您的应用程序,从而删除了重新启动后进行的自注册。 我认为使您的“窗口小部件应用程序”尽可能轻(需要尽可能少的内存和CPU资源...)是确保您的窗口小部件应用程序仅在设备严重情况下被杀死的正确方法。 。也许您应该将大型应用程序一分为二,为需要不时工作的重量级应用程序创建一个小部件启动器……

答案 1 :(得分:0)

解决方案是我已经完成的两次尝试的组合。

首先,我必须使用粘性通知启动前台服务(即使是虚拟服务也不错):

   Function downloadFile() {
        var level = 1;
        if(onlyComplete === true){
            level = 2;
        }
        DownloadValues(function(downloadFields) {
            downloadFields.push("group");
            var user_subscription = "free";
            var csv_data_length = 600;
            if(user_subscription == "paid")
                csv_data_length = users.length;
            var users_ = sort_(users); /** called sort function **/
    ..........
    }

}

当然,您在服务开始时必须使用public class StartDetectionAtBoot extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { Intent intent1 = new Intent(context.getApplicationContext(), DummyService.class); context.startForegroundService(intent1); } Intent intent0 = new Intent( context, ActivityRecognitionService.class ); PendingIntent pendingIntent = PendingIntent.getService(context, 111, intent0, PendingIntent.FLAG_UPDATE_CURRENT); ActivityRecognitionClient activityRecognitionClient = ActivityRecognition.getClient(context); activityRecognitionClient.requestActivityUpdates(5000, pendingIntent); } } 方法创建通知并调用onCreate

其次,我在Android Studio中进行了缓存失效,我也擦除了模拟器实例。这部分解决方案对我来说是非常必要的,因为第一部分仍然没有用。

答案 2 :(得分:0)

W/BroadcastQueue:不允许后台执行:receiving Intent { act=android.intent.action.BOOT_COMPLETED **flg=0x400010** }

您从 adb shell 测试意图,可能是 am broadcast -a android.intent.action.BOOT_COMPLETED flg=0x400010 与 Android 系统在启动时发送的 flg=0x9000010 不同。

您可以在 frameworks/base/core/java/android/content/Intent.java 处找到标志定义。 flg=0x400010 没有 FLAG_RECEIVER_FOREGROUND = 0x10000000 位。

所以,如果你想从 adb shell 测试意图,你可以使用 am broadcast -a android.intent.action.BOOT_COMPLETED *--receiver-include-background.*