Android 8.0: java.lang.IllegalStateException: не разрешено запускать сервис Intent

При запуске приложения приложение запускает службу, которая должна выполнять некоторую сетевую задачу. После настройки уровня API на уровне 26 мое приложение не запускает службу на Android 8.0 на фоне.

Причина: java.lang.IllegalStateException: Не разрешено запускать сервис Intent {cmp = my.app.tt / com.my.service}: приложение находится в фоновом режиме uidRecord {90372b1 u0a136 CEM idle procs: 1 seq (0,0 , 0)}

как я понимаю, это связано с: лимитами исполнения

Метод startService () теперь выдает исключение IllegalStateException, если приложение, ориентированное на Android 8.0, пытается использовать этот метод в ситуации, когда не разрешено создавать фоновые службы.

« в ситуации, когда это не разрешено » – что это на самом деле означает? И как это исправить. Я не хочу, чтобы моя служба была «передним планом»,

    Разрешенные ситуации – это временный белый список, где фоновый сервис ведет себя так же, как и до Android O.

    При определенных обстоятельствах фоновое приложение помещается во временный белый список в течение нескольких минут. Хотя приложение находится в белом списке, оно может запускать службы без ограничений, и его фоновым службам разрешено работать. Приложение помещается в белый список, когда он обрабатывает задачу, которая видна пользователю, например:

    • Обработка сообщения с приоритетными сообщениями Firebase Cloud Messaging (FCM).
    • Получение широковещательной передачи, например, сообщение SMS / MMS.
    • Выполнение PendingIntent из уведомления.
    • Запуск VpnService до того, как приложение VPN продвинется на передний план.

    Источник: https://developer.android.com/about/versions/oreo/background.html

    То есть, если ваш фоновый сервис не соответствует требованиям «белых списков», вам нужно использовать новый JobScheduler . Это в основном то же самое, что и фоновое обслуживание, но оно периодически вызывается, а не работает в фоновом режиме непрерывно.

    Я получил решение. Для устройств pre-8.0 вам нужно просто использовать startService() , но для устройств после 7.0 вы должны использовать startForgroundService() . Вот пример кода для запуска службы.

     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { context.startForegroundService(new Intent(context, ServedService.class)); } else { context.startService(new Intent(context, ServedService.class)); } 

    И в classе обслуживания, пожалуйста, добавьте код для уведомления:

     @Override public void onCreate() { super.onCreate(); startForeground(1,new Notification()); } 

    Где O – Android версии 26.

    Надеюсь, что это решит IllegalArgumentException

    Если служба работает в фоновом streamе, расширяя IntentService , вы можете заменить IntentService на JobIntentService который предоставляется как часть библиотеки поддержки Android

    Преимущество использования JobIntentService заключается в том, что он ведет себя как IntentService на устройствах pre-O и на O и выше, он отправляет его как задание

    JobScheduler также может использоваться для периодических / по требованию заданий. Но, чтобы обеспечить обратную совместимость, поскольку JobScheduler API доступен только из API 21

    Лучший способ – использовать JobIntentService, который использует новый JobScheduler для Oreo или старых сервисов, если он недоступен.

    Объявите в своем манифесте:

      

    И в вашем сервисе вам нужно заменить onHandleIntent на onHandleWork:

     public class YourService extends JobIntentService { public static final int JOB_ID = 1; public static void enqueueWork(Context context, Intent work) { enqueueWork(context, YourService.class, JOB_ID, work); } @Override protected void onHandleWork(@NonNull Intent intent) { // your code } } 

    Затем вы начинаете свою службу с:

     YourService.enqueueWork(context, new Intent()); 

    Да, это потому, что вы больше не можете запускать службы в фоновом режиме на API 26. Таким образом, вы можете запустить ForegroundService выше API 26.

    Вы должны будете использовать

     ContextCompat.startForegroundService(...) 

    и отправлять уведомление при обработке утечки.

    Из заметок о выпуске firebase говорится , что поддержка Android O была впервые выпущена в 10.2.1 (хотя я бы рекомендовал использовать самую последнюю версию).

    добавьте новые зависимости обмена сообщениями firebase для android O

     compile 'com.google.firebase:firebase-messaging:11.6.2' 

    обновите сервисы google play и репозитории google, если это необходимо.

    если вы включили push-оповещение об обмене сообщениями firebase,

    Добавьте новые / обновленные зависимости обмена сообщениями firebase для Android O (Android 8.0) из-за ограничений фона .

     compile 'com.google.firebase:firebase-messaging:11.4.0' 

    обновите сервисы google play и репозитории google, если это необходимо.

    Обновить:

      compile 'com.google.firebase:firebase-messaging:11.4.2' 

    Используйте startForegroundService() вместо startService() и не забудьте создать startForeground(1,new Notification()); в вашем сервисе в течение 5 секунд после начала обслуживания.

    Другие ответы правильны, но я хотел бы отметить, что другой способ обойти это – попросить пользователя отключить оптимизацию батареи для вашего приложения (это обычно не рекомендуется, если ваше приложение не связано с системой). См. Этот ответ о том, как запросить отказ от оптимизации батареи без запрета вашего приложения в Google Play.

    Вы также должны проверить, отключены ли батареи в приемнике, чтобы предотвратить сбои через:

     if (Build.VERSION.SDK_INT < 26 || getSystemService() ?.isIgnoringBatteryOptimizations(packageName) != false) { startService(Intent(context, MyService::class.java)) } // else calling startService will result in crash 

    – Первый метод вызова в стартовом приложении или основной деятельности:

     public static void createChancelNotification(Context mContext) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); NotificationChannel androidChannel = new NotificationChannel(Constants.ANDROID_CHANNEL_ID, Constants.ANDROID_CHANNEL_NAME, NotificationManager.IMPORTANCE_MAX); notificationManager.createNotificationChannel(androidChannel); } } 

    – Второй, когда закрытие приложения и firebase push:

     public class FirebaseDataReceiver extends WakefulBroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { if (intent.getExtras() != null) { for (String key : intent.getExtras().keySet()) { Object value = intent.getExtras().get(key); Log.e("FirebaseDataReceiver", "Key: " + key + " Value: " + value); } } if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { // Attach component of GCMIntentService that will handle the intent in background thread ComponentName componentName = new ComponentName(context.getPackageName(), MyFirebaseMessageService.class.getName()); // Start the service, keeping the device awake while it is launching. startWakefulService(context, intent.setComponent(componentName)); setResultCode(Activity.RESULT_OK); } } 

    }

    - Последний дескриптор в файле:

     public class MyFirebaseMessageService extends FirebaseMessagingService { private static final String TAG = MyFirebaseMessageService.class.getSimpleName(); @Override public void onMessageReceived(RemoteMessage remoteMessage) { if (remoteMessage.getData() != null) { // Do some thing here } } 

    не использовать в onStartCommand:

     return START_NOT_STICKY 

    просто измените его на:

     return START_STICKY 

    и он будет работать

    Давайте будем гением компьютера.