完美解决 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);
}
大功告成,希望能够帮到更多的人!!!