当前位置:   article > 正文

Android Service 系列2. Android开机启动Service和“ did not then call Service.startForeground()”异常

Android Service 系列2. Android开机启动Service和“ did not then call Service.startForeground()”异常

本文目录

1 需求

2 安卓开机自启服务

2.1 定义广播接收器

2.2 声明

3 服务启动时出现的crash问题

3.1 原因分析

3.2 解决方案

3.2.1 添加权限

3.2.2 在广播接收器里根据安卓版本确定启动server的方式

3.2.3 创建服务后,需要在5秒内调用服务的 startForeground() 显示一条可见通知


1 需求

项目需要Android设备开机后,自动启动一个后台服务。

在实现过程中发现,安卓版本在8.0之后,在启动服务时会频繁出现下述异常:

“Context.startForegroundService() did not then call Service.startForeground()”

下面依次讲述如何实现Android开机自启服务和异常处理的方法。 

2 安卓开机自启服务

实现思路:定义广播接收器,在android系统开机时,后台启动服务。

2.1 定义广播接收器

  1. public class BootReceiver extends BroadcastReceiver {
  2. @Override
  3. public void onReceive(Context context, Intent intent) {
  4. // 检查是否是开机广播
  5. if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
  6. Log.v("BootReceiver","BootReceiver");
  7. //开启服务
  8. Intent intent = new Intent(context, TestService.class );
  9. intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//需要增加,否则会报错
  10. context.startService(intent);
  11. }
  12. }

2.2 声明

 在AndroidManifest.xml里声明广播接收器。

  1. <receiver
  2. android:name=".BootReceiver"
  3. android:enabled="true"
  4. android:exported="true">
  5. <intent-filter>
  6. <action android:name="android.intent.action.BOOT_COMPLETED" />
  7. </intent-filter>
  8. </receiver>

3 服务启动时出现的crash问题

3.1 原因分析

  1. Android 8.0 不再允许后台service直接通过startService方式去启动,否则就会引起IllegalStateException。
  2. 因此在Android 8.0 中,需要在前台启动新服务,即 Context.startForegroundService()
  3. 在系统创建服务后,应用有5秒的时间来调用该服务的 startForeground() 方法以显示新服务的用户可见通知。
  4. 如果应用在此时间限制内未调用 startForeground(),则系统将停止服务并声明此应用为 ANR。

3.2 解决方案

3.2.1 添加权限

  1. <!--android 9.0上使用前台服务,需要添加权限,此权限为级别为nomarl-->
  2. <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

3.2.2 在广播接收器里根据安卓版本确定启动server的方式

  1. public class BootReceiver extends BroadcastReceiver {
  2. @Override
  3. public void onReceive(Context context, Intent intent) {
  4. // 检查是否是开机广播
  5. if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
  6. Log.v("BootReceiver","BootReceiver");
  7. //开启服务
  8. Intent intent = new Intent(context, TestService.class );
  9. intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//需要增加,否则会报错
  10. context.startService(intent);
  11. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {//安卓8.0之后
  12. context.startForegroundService(new Intent(context, TestService.class));
  13. } else {
  14. context.startService(new Intent(context, TestService.class));
  15. }
  16. }
  17. }

3.2.3 创建服务后,需要在5秒内调用服务的 startForeground() 显示一条可见通知

在Server中onStartCommand()方法中调用startForeground(),声明有服务在挂着,否则系统会停止服务,提示异常。

  1. public static final String CHANNEL_ID_STRING = "id";
  2. public static final String CHANNEL_NAME_STRING = "name";
  3. private Notification notification;
  4. @Override
  5. public int onStartCommand(Intent intent, int flags, int startId) {
  6. //适配8.0service
  7. NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
  8. NotificationChannel mChannel = null;
  9. if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
  10. mChannel = new NotificationChannel(CHANNEL_ID_STRING, CHANNEL_NAME_STRING, NotificationManager.IMPORTANCE_LOW);
  11. notificationManager.createNotificationChannel(mChannel);
  12. notification = new Notification.Builder(getApplicationContext(), CHANNEL_ID_STRING).build();
  13. startForeground(1, notification);
  14. }
  15. //其他初始化操作...
  16. return super.onStartCommand(intent, flags, startId);
  17. }

  

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号