完美解决android 8.0 以上 开启Service异常

完美解决 android 8.0 以上 开启Service: IllegalStateException: Not allowed to start service Intent ... 异常

简要:

  • android 8.0 应用处于后台运行时,不允许 startService方式开启服务,否则抛出异常
IllegalStateException: Not allowed to start service Intent ...
  • android 8.0 应用在后台运行大于1min时,会默认杀死后台服务

解决方案:

1. Service 改成 JobIntentService ,具体使用可查询

2. 将 startService改成startForegroundService,后台服务提升成了前台服务,但是 需要在开启服务的5s内需要调用startForeground 函数,否则,会抛出ANR

020-12-13 21:02:37.547 1777-2025/? E/ActivityManager: ANR in com.example.demo
    PID: 30328
    Reason: Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{7b4e645 u0 com.example.demo/.Myservice}
    Load: 0.0 / 0.0 / 0.0
    CPU usage from 18173ms to 0ms ago (2020-12-13 21:02:19.180 to 2020-12-13 21:02:37.353):
      35% 1777/system_server: 25% user + 10% kernel / faults: 81735 minor 29 major
      9% 893/surfaceflinger: 6.2% user + 2.7% kernel / faults: 167 minor
      8.6% 533/logd: 6.1% user + 2.4% kernel / faults: 5 minor
      7.5% 2929/com.miui.home: 5.6% user + 1.8% kernel / faults: 6818 minor 1 major
      6.6% 1078/installd: 0.3% user + 6.2% kernel / faults: 1254 minor
      3% 2570/com.android.systemui: 2.2% user + 0.8% kernel / faults: 2247 minor
      2.8% 782/vendor.qti.hardware.display.composer-service: 1.4% user + 1.3% kernel / faults: 21 minor
      2.7% 18275/adbd: 0.6% user + 2% kernel / faults: 1772 minor
      1.3% 15574/com.miui.systemAdSolution: 0.8% user + 0.4% kernel / faults: 4088 minor 9 major
      2.3% 15867/com.ss.android.article.lite: 1.9% user + 0.4% kernel / faults: 2009 minor
      2.3% 26598/kworker/u16:7-kverityd: 0% user + 2.3% kernel / faults: 61 minor
      1.9% 12042/com.xiaomi.market: 1.3% user + 0.6% kernel / faults: 2153 minor
      0% 353/mi_reclaim: 0% user + 0% kernel
      1.7% 25160/com.hunantv.imgo.activity: 1.3% user + 0.4% kernel / faults: 1686 minor
      1.5% 164/kswapd0: 0% user + 1.5% kernel
      1.5% 2901/com.android.phone: 0.8% user + 0.6% kernel / faults: 1110 minor
      1.5% 4191/com.miui.securitycenter.remote: 1.2% user + 0.3% kernel / faults: 1525 minor
      1.1% 26602/kworker/u16:16-kverityd: 0% user + 1.1% kernel / faults: 23 minor
      1% 22728/kworker/u17:0-dwc_wq: 0% user + 1% kernel
      0.8% 383/crtc_commit:109: 0% user + 0.8% kernel
      0.8% 26599/kworker/u16:11-ufs_pm_qos_0: 0% user + 0.8% kernel / faults: 27 minor
      0.7% 772/android.hardware.sensors@1.0-service: 0.3% user + 0.4% kernel
      0.7% 883/lmkd: 0% user + 0.7% kernel
      0.7% 10193/kworker/u16:10+CDSP_CNTL: 0% user + 0.7% kernel / faults: 18 minor
      0.7% 22711/kworker/u16:4-ufs_pm_qos_0: 0% user + 0.7% kernel / faults: 14 minor
      0.3% 14660/com.qualcomm.qti.workloadclassifier: 0.2% user + 0% kernel / faults: 1302 minor
      0.6% 26605/com.tencent.mobileqq: 0.3% user + 0.2% kernel / faults: 405 minor
      0.4% 3507/irq/113-90b6300: 0% user + 0.4% kernel
      0.4% 15289/com.xunmeng.pinduoduo:titan: 0.3% user + 0.1% kernel / faults: 517 minor
      0.4% 17946/kworker/u17:2-fts-event-queue: 0% user + 0.4% kernel
      0.4% 534/servicemanager: 0.1% user + 0.3% kernel
      0.4% 786/vendor.qti.hardware.perf@2.0-service: 0.1% user + 0.2% kernel / faults: 122 minor
      0.2% 25367/com.miui.weather2: 0.1% user + 0% kernel / faults: 732 minor
      0.4% 30328/com.example.demo: 0.3% user + 0% kernel / faults: 707 minor
      0.3% 11682/kworker/u16:17-kverityd: 0% user + 0.3% kernel / faults: 12 minor
      0.3% 27220/com.tencent.mobileqq:mini: 0.1% user + 0.2% kernel / faults: 53 minor
      0.3% 28241/com.eg.android.AlipayGphone: 0.2% user + 0.1% kernel / faults: 72 minor
      0.3% 115/system: 0% user + 0.3% kernel
      0.3% 1062/cnss_diag: 0.2% user + 0.1% kernel
      0.3% 3509/irq/114-90cd000: 0% user + 0.3% kernel
      0.3% 6742/com.miui.powerkeeper: 0.1% user + 0.2% kernel / faults: 98 minor
      0.2% 11/rcu_preempt: 0% user + 0.2% kernel
      0.2% 12664/com.youdao.dict: 0.2% user + 0% kernel / faults: 402 minor
      0.2% 25514/com.smile.gifmaker: 0.1% user + 0.1% kernel / faults: 171 minor

我们可以在Service的onCreat方法中调用startForeground 函数,有个问题就是这个函数调用之后会显示一个通知栏,提醒用户某个服务在运行

                                                                              

但是有些需求后者用户不想看到这个通知栏,我们就要把去掉,去掉这个通知栏是非常难办的,所以就要想想特殊的办法了

重点来了:

大体思路是:一个最后保留的MyService,一个辅助消除通知的MyService1, 利用 MyService去绑定MyService1,startForeground变为前台服务,注意一定要使用一样的Notification ID,然后MyService1取消前台效果stopForeground从而删除通知。

目的:

一.添加权限

  <!--service前台服务-->
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

二 .主服务

package com.example.demo;

import android.app.Service;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;
import android.util.Log;

import androidx.annotation.RequiresApi;

/**
 * @author: ding xujun
 * @created on: 2020/12/10 23:01
 * @project: demo
 */
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public class Myservice extends Service {
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    public void onCreate() {
        super.onCreate();
        Log.d("Myservice=======", "onCreate");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            startForeground(ServiceNotificationManager.NOTIFICATION_FOREGROUND_ID, ServiceNotificationManager.getNotification(this));
            Intent intent = new Intent(this, Myservice1.class);
            startForegroundService(intent);
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("Myservice=======", "onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }


    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("Myservice=======", "onDestroy");
    }
}

三.辅助取消通知栏的服务

package com.example.demo;

import android.app.Service;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;
import android.util.Log;

import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;

/**
 * @author: ding xujun
 * @created on: 2020/12/13 11:54
 * @project: demo
 */
public class Myservice1 extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        startForeground(ServiceNotificationManager.NOTIFICATION_FOREGROUND_ID, ServiceNotificationManager.getNotification(this));
        Log.d("Myservice=======", "onCreate1");
        stopSelf();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("Myservice=======", "onStartCommand1");
        return super.onStartCommand(intent, flags, startId);
    }

    @RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    public void onDestroy() {
        super.onDestroy();
        //stopForeground 停止服务并且取消通知栏 ,这种情况比较特殊,
        // 所以还要调用ServiceNotificationManager.removeNotification();
        ServiceNotificationManager.removeNotification();
        stopForeground(true);
        Log.d("Myservice=======", "onDestroy1");
    }

}

三.工具类

package com.example.demo;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.os.Build;

import androidx.annotation.RequiresApi;

/**
 * @author: ding xujun
 * @created on: 2020/12/13 11:56
 * @project: demo
 */
public class ServiceNotificationManager {

    public static Notification mNotification = null;
    private static NotificationChannel mChannel = null;
    private static NotificationManager mNotificationManager;
    private static final String NOTIFICATION_CHANNEL_ID = "1";
    public static final int NOTIFICATION_FOREGROUND_ID = 1;

    public static Notification getNotification(Context context) {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            if (mNotificationManager == null) {
                mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
            }
            if (mChannel == null) {
                mChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, context.getString(R.string.app_name), NotificationManager.IMPORTANCE_HIGH);
            }
            mNotificationManager.createNotificationChannel(mChannel);
            if (mNotification == null) {
                mNotification = new Notification.Builder(context, NOTIFICATION_CHANNEL_ID).build();
            }
        }
        return mNotification;
    }

    @RequiresApi(api = Build.VERSION_CODES.O)
    public static void removeNotification() {
        if (mNotificationManager == null) {
            return;
        }
        mNotificationManager.cancel(NOTIFICATION_FOREGROUND_ID);
        mNotificationManager.deleteNotificationChannel(NOTIFICATION_CHANNEL_ID);
    }
}

四.开启服务

  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
     startForegroundService(intent);
   } else {
     startService(intent);
   }

大功告成,希望能够帮到更多的人!!!

 

 

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Android 8.0 及以上版本,为了增强应用程序的安全性,Android 引入了后台限制,禁止未在前台运行的应用程序启动服务。如果您想在后台启动服务,需要使用 `startForegroundService()` 方法。这个方法会启动一个前台服务,然后你可以在服务启动后在通知栏显示一个通知,以此来告知用户服务正在运行。 以下是一个使用 `startForegroundService()` 的示例代码: ``` if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // 创建一个 NotificationChannel NotificationChannel channel = new NotificationChannel("channel_id", "channel_name", NotificationManager.IMPORTANCE_DEFAULT); // 向系统注册 NotificationChannel NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); notificationManager.createNotificationChannel(channel); } // 创建一个 Intent,启动你的服务 Intent serviceIntent = new Intent(this, YourService.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // 在 Android 8.0 及以上版本上,需要调用 startForegroundService() 方法启动服务。 startForegroundService(serviceIntent); } else { // 在 Android 8.0 以下版本上,可以直接调用 startService() 方法启动服务。 startService(serviceIntent); } ``` 注意:如果你使用的是 `startForeground()` 方法,会在 Android 8.0 及以上版本上抛出 `IllegalStateException` 异常,因为 Android 8.0 及以上版本禁止在后台启动服务。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值