首页 文章

Android 8.0:java.lang.IllegalStateException:不允许启动服务Intent

提问于
浏览
188

在应用程序启动时,应用程序启动应该执行某些网络任务的服务 . 在针对API级别26后,我的应用程序无法在后台启动Android 8.0上的服务 .

引起:java.lang.IllegalStateException:不允许启动服务Intent {cmp = my.app.tt / com.my.service}:app在后台uid UidRecord {90372b1 u0a136 CEM idle procs:1 seq(0, 0,0)}

据我所知,它与:Background execution limits有关

如果针对Android 8.0的应用程序在不允许创建后台服务的情况下尝试使用该方法,则startService()方法现在会抛出IllegalStateException .

in a situation when it isn't permitted " - what it's actually mean?? And how to fix it. I don't want to set my service as "前景”

13 回答

  • 10

    不要在onStartCommand中使用:

    return START_NOT_STICKY
    

    只需将其更改为:

    return START_STICKY
    

    它会起作用

  • 104

    是的,那是因为你无法在API 26中在后台启动服务 . 所以你可以在API 26之上启动ForegroundService .

    你必须使用

    ContextCompat.startForegroundService(...)
    

    并在处理泄漏时发布通知 .

  • -3

    如果你已经集成了firebase消息传递推送通知,那么,

    由于Background Execution Limits,为Android O(Android 8.0)添加新的/更新firebase消息传递依赖项 .

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

    如果需要,升级谷歌播放服务和谷歌存储库 .

    Update:

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

    如果您在8.0上运行代码,那么应用程序将崩溃 . 所以在前台启动服务 . 如果低于8.0使用此:

    Intent serviceIntent = new Intent(context, RingtonePlayingService.class);
    context.startService(serviceIntent);
    

    如果高于或高于8.0则使用此:

    Intent serviceIntent = new Intent(context, RingtonePlayingService.class);
    ContextCompat.startForegroundService(context, serviceIntent );
    
  • 0

    其他答案都是正确的,但我通常是一个好主意,除非你的应用程序是系统相关的) . 请参阅this answer了解如何在未在Google Play中禁止您的应用的情况下请求退出电池优化 .

    您还应该检查接收器中的电池优化是否已关闭,以防止崩溃:

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

    允许的情况是临时白名单,其中后台服务的行为与Android O之前相同 .

    在某些情况下,后台应用程序会在临时白名单上放置几分钟 . 虽然应用程序位于白名单中,但它可以无限制地启动服务,并允许其后台服务运行 . 当应用程序处理用户可见的任务时,应用程序将放置在白名单中,例如:处理高优先级的Firebase Cloud 消息传递(FCM)消息 . 接收广播,例如SMS / MMS消息 . 从通知执行PendingIntent . 在VPN应用程序将自身提升到前台之前启动VpnService .

    资料来源:https://developer.android.com/about/versions/oreo/background.html

    换句话说,如果您的后台服务不符合白名单要求,则必须使用新的JobScheduler . 它与后台服务基本相同,但它会定期调用,而不是连续在后台运行 .

    如果你're using an IntentService, you can change to a JobIntentService. See @kosev' s answer below .

  • 1

    我得到了解决方案对于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));
        }
    

    在服务类中,请添加以下代码以获取通知:

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

    其中O是Android版本26 .

    希望它能解决 IllegalArgumentException

  • -9

    - The first call method in start app or main activity:

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

    - The Second when close app and 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);
        }
    
    }
    

    }

    - The last handle in file:

    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
        }
    }
    
  • 1

    使用 startForegroundService() 而不是 startService() 并且不要忘记在启动服务的5秒内在服务中创建 startForeground(1,new Notification()); .

  • -2

    如果服务通过扩展 IntentService 在后台线程中运行,则可以将 IntentService 替换为 JobIntentService ,它是作为Android支持库的一部分提供的

    使用 JobIntentService 的优点是,它在pre-O设备上表现为 IntentService ,在O和更高的设备上,它将其作为一项工作发送

    JobScheduler 也可用于定期/按需作业 . 但是,请确保处理向后兼容性,因为 JobScheduler API仅可从API 21获得

  • 120

    firebase release notes开始,他们表示对Android O的支持首次在10.2.1中发布(尽管我建议使用最新版本) .

    请为android O添加新的firebase消息依赖项

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

    如果需要,升级谷歌播放服务和谷歌存储库 .

  • 25

    我看到很多回复建议只使用ForegroundService . 要使用ForegroundService,必须有与之关联的通知 . 用户将看到此通知 . 根据具体情况,他们可能会对您的应用程序感到恼火并将其卸载 .

    最简单的解决方案是使用名为WorkManager的新架构组件 . 你可以在这里查看文档:https://developer.android.com/topic/libraries/architecture/workmanager/

    您只需定义扩展Worker的工作类 .

    public class CompressWorker extends Worker {
    
        public CompressWorker(
            @NonNull Context context,
            @NonNull WorkerParameters params) {
            super(context, params);
        }
    
        @Override
        public Worker.Result doWork() {
    
            // Do the work here--in this case, compress the stored images.
            // In this example no parameters are passed; the task is
            // assumed to be "compress the whole library."
            myCompress();
    
            // Indicate success or failure with your return value:
            return Result.SUCCESS;
    
            // (Returning RETRY tells WorkManager to try this task again
            // later; FAILURE says not to try again.)
        }
    }
    

    然后安排何时运行它 .

    OneTimeWorkRequest compressionWork = 
            new OneTimeWorkRequest.Builder(CompressWorker.class)
                .build();
        WorkManager.getInstance().enqueue(compressionWork);
    

    简单!您可以通过多种方式配置工作人员 . 它支持重复性工作,如果需要,您甚至可以执行链接等复杂操作 . 希望这可以帮助 .

  • 2

    最好的方法是使用JobIntentService,它使用新的JobScheduler for Oreo或旧服务(如果不可用) .

    在你的清单中声明:

    <service android:name=".YourService"
             android:permission="android.permission.BIND_JOB_SERVICE"/>
    

    在您的服务中,您必须使用onHandleWork替换onHandleIntent:

    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());
    

相关问题