Android14新特性 开启前台service服务

1. Android14新特性

1.1. 场景

**  在Android14(targetSDK=34)系统手机开启前台service服务崩溃**

javascript 复制代码
ATAL EXCEPTION: main
                 Process: com.inspur.lbrd, PID: 15634
                 java.lang.RuntimeException: Unable to create service com.inspur.lbrd.service.KeepAliveService: android.app.MissingForegroundServiceTypeException: Starting FGS without a type  callerApp=ProcessRecord{957facf 15634:com.inspur.lbrd/u0a352} targetSDK=34
                 	at android.app.ActivityThread.handleCreateService(ActivityThread.java:5182)
                 	at android.app.ActivityThread.-$$Nest$mhandleCreateService(Unknown Source:0)
                 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2638)
                 	at android.os.Handler.dispatchMessage(Handler.java:108)
                 	at android.os.Looper.loopOnce(Looper.java:226)
                 	at android.os.Looper.loop(Looper.java:328)
                 	at android.app.ActivityThread.main(ActivityThread.java:9128)
                 	at java.lang.reflect.Method.invoke(Native Method)
                 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:586)
                 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
                 Caused by: android.app.MissingForegroundServiceTypeException: Starting FGS without a type  callerApp=ProcessRecord{957facf 15634:com.inspur.lbrd/u0a352} targetSDK=34
                 	at android.app.MissingForegroundServiceTypeException$1.createFromParcel(MissingForegroundServiceTypeException.java:53)
                 	at android.app.MissingForegroundServiceTypeException$1.createFromParcel(MissingForegroundServiceTypeException.java:49)
                 	at android.os.Parcel.readParcelableInternal(Parcel.java:4884)
                 	at android.os.Parcel.readParcelable(Parcel.java:4866)
                 	at android.os.Parcel.createExceptionOrNull(Parcel.java:3066)
                 	at android.os.Parcel.createException(Parcel.java:3055)
                 	at android.os.Parcel.readException(Parcel.java:3038)
                 	at android.os.Parcel.readException(Parcel.java:2980)
                 	at android.app.IActivityManager$Stub$Proxy.setServiceForeground(IActivityManager.java:7415)
                 	at android.app.Service.startForeground(Service.java:775)
                 	at com.inspur.lbrd.service.KeepAliveService.setForeground(SourceFile:118)
                 	at com.inspur.lbrd.service.KeepAliveService.onCreate(SourceFile:32)
                 	at android.app.ActivityThread.handleCreateService(ActivityThread.java:5169)
                 	at android.app.ActivityThread.-$$Nest$mhandleCreateService(Unknown Source:0) 
                 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2638) 
                 	at android.os.Handler.dispatchMessage(Handler.java:108) 
                 	at android.os.Looper.loopOnce(Looper.java:226) 
                 	at android.os.Looper.loop(Looper.java:328) 
                 	at android.app.ActivityThread.main(ActivityThread.java:9128) 
                 	at java.lang.reflect.Method.invoke(Native Method) 
                 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:586) 
                 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099) 

1.2. 解决方案

1.2.1. 在清单文件AndroidManifest.xml添加权限和配置

javascript 复制代码
 <!-- android14前台常住服务权限-->
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
javascript 复制代码
  <service
      android:name=".service.KeepAliveService"
      android:foregroundServiceType="location" />

1.2.2. service服务

javascript 复制代码
public class KeepAliveService extends Service {
    private final String TAG = "szyj_GridTraceS-";

    public KeepAliveService() {
    }
    @Override
    public void onCreate() {
        super.onCreate();
        // 添加常驻通知栏
        setForeground();
       // startXcService();
    }
    private void startXcService() {
        try {
            String patrolStatus = SpUtil.getInstance(this).getString(
                    GridTraceConstant.SP_PATROL_STATUS,
                    GridTraceConstant.SP_PATROL_STATUS_FALSE);
            //巡查服务已开启
            if (TextUtils.equals(patrolStatus, GridTraceConstant.SP_PATROL_STATUS_TRUE)) {
                if (!ServiceUtil.isServiceRunning(this, GridTraceService.class.getName())) {
                    startService(new Intent(this, GridTraceService.class));
                }
            } else {//未开启巡查服务
                if (ServiceUtil.isServiceRunning(this, GridTraceService.class.getName())) {
                    stopService(new Intent(this, GridTraceService.class));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        //可将onStartCommand() 方法的返回值设为 START_STICKY或START_REDELIVER_INTENT ,
        //该值表示服务在内存资源紧张时被杀死后,在内存资源足够时再恢复。
        //也可将Service设置为前台服务,这样就有比较高的优先级,在内存资源紧张时也不会被杀掉。
        return START_STICKY;
        //return super.onStartCommand(intent, flags, startId);
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        // 删除图标
        stopForeground(true);
    }

    @Override
    public IBinder onBind(Intent intent) {
        throw new UnsupportedOperationException("Not yet implemented");
    }
    /**
     * 添加常驻通知栏
     */
    private void setForeground() {
        NotificationManager notificationManager = (NotificationManager) getSystemService
                (Context.NOTIFICATION_SERVICE);
        String notificationId = "serviceid";
        String notificationName = "servicename";
        int noticeId = 2;
        Notification.Builder builder = new Notification.Builder(this);
        //创建NotificationChannel
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(notificationId,
                    notificationName, NotificationManager.IMPORTANCE_HIGH);
            channel.enableLights(true);//设置高亮(选填)
            channel.setShowBadge(true);//设置角标(选填)
            //设置锁屏可见(选填)
            channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
            notificationManager.createNotificationChannel(channel);
            builder.setChannelId(notificationId);
        }
        Intent intent = new Intent(KeepAliveService.this, MainActivity.class);
        PendingIntent pendingIntent;
        //Android12
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
            pendingIntent = PendingIntent.getActivity(this,
                    123, intent, PendingIntent.FLAG_IMMUTABLE);
        } else {
            pendingIntent = PendingIntent.getActivity(this,
                    123, intent, PendingIntent.FLAG_ONE_SHOT
                            | PendingIntent.FLAG_MUTABLE);
        }
        builder.setSmallIcon(R.mipmap.icon_app)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(),
                        R.mipmap.icon_app))
                .setContentTitle(getString(R.string.app_name))//选填
                .setContentText(getString(R.string.app_name))//选填
                .setWhen(System.currentTimeMillis())
                .setContentIntent(pendingIntent);
        Notification notification = builder.build();
        startForeground(noticeId, notification);
    }
}

1.2.2. 启动service服务

javascript 复制代码
  if (!ServiceUtil.isServiceRunning(this, KeepAliveService.class.getName())) {
            startService(new Intent(this, KeepAliveService.class));
        }

&emsp;&emsp;判断服务是否开启

javascript 复制代码
public class ServiceUtil {
    /**
     * @param context
     * @param className service后台服务名称
     * @return
     * @desc 查询service是否在运行
     */
    public static boolean isServiceRunning(Context context, String className) {
        ActivityManager activityManager = (ActivityManager) context
                .getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningServiceInfo> serviceList = activityManager
                .getRunningServices(Integer.MAX_VALUE);

        if (!(serviceList.size() > 0)) {
            return false;
        }

        for (int i = 0; i < serviceList.size(); i++) {
            ActivityManager.RunningServiceInfo serviceInfo = serviceList.get(i);
            ComponentName serviceName = serviceInfo.service;

            if (serviceName.getClassName().equals(className)) {
                return true;
            }
        }
        return false;
    }
}
相关推荐
Yeats_Liao11 分钟前
Spring 定时任务:@Scheduled 注解四大参数解析
android·java·spring
雾里看山2 小时前
【MySQL】 库的操作
android·数据库·笔记·mysql
水瓶丫头站住10 小时前
安卓APP如何适配不同的手机分辨率
android·智能手机
xvch11 小时前
Kotlin 2.1.0 入门教程(五)
android·kotlin
xvch15 小时前
Kotlin 2.1.0 入门教程(七)
android·kotlin
望风的懒蜗牛15 小时前
编译Android平台使用的FFmpeg库
android
浩宇软件开发16 小时前
Android开发,待办事项提醒App的设计与实现(个人中心页)
android·android studio·android开发
ac-er888816 小时前
Yii框架中的多语言支持:如何实现国际化
android·开发语言·php
苏金标17 小时前
The maximum compatible Gradle JVM version is 17.
android
zhangphil17 小时前
Android BitmapShader简洁实现马赛克,Kotlin(一)
android·kotlin