Android8.0 后台服务保活的一种思路

原文地址:Android8.0 后台服务保活的一种思路 | Stars-One的杂货小窝

项目中有个MQ服务,需要一直连着,接收到消息会发送语音,且手机要在锁屏也要实现此功能

目前是使用广播机制实现,每次MQ收到消息,触发一次启动服务操作逻辑

在Android11版本测试成功,可实现上述功能

步骤

具体流程:

  1. 进入APP
  2. 开启后台服务Service
  3. 后台服务Service开启线程,连接MQ
  4. MQ的消费事件,发送广播
  5. 广播接收器中,处理启动服务(若服务已被关闭)和文本语音播放功能

1.广播注册

<receiver     android:name=".receiver.MyReceiver"     android:enabled="true"     android:exported="true"> </receiver> 
public class MyReceiver extends BroadcastReceiver {      @Override     public void onReceive(Context context, Intent intent) {         String action = intent.getAction();         //匹配下之前定义的action         if ("OPEN_SERVICE".equals(action)) {             if (!ServiceUtils.isServiceRunning(MqMsgService.class)) {                 Log.e("--test", "服务未启动,先启动服务");                 Intent myIntent = new Intent(context, MqMsgService.class);                 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {                     context.startForegroundService(intent);                 } else {                     context.startService(intent);                 }              }              String text = intent.getStringExtra("text");             Log.e("--test", "广播传的消息"+text);              EventBus.getDefault().post(new SpeakEvent(text));         }     } } 

语音初始化的相关操作都在服务中进行的,这里不再赘述(通过EventBus转发时间事件)

这里需要注意的是,Android8.0版本,广播不能直接startService()启动服务,而是要通过startForegroundService()方法,而调用了startForegroundService()方法,则是需要服务在5s内调用一个方法startForeground()

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {     Notification notification = NotifyUtil.sendNotification(this, "平板", "后台MQ服务运行中", NotificationCompat.PRIORITY_HIGH);     startForeground(1, notification); } 

上面这段代码,就是写在Service中的onCreate方法内,之前也是找到有资料说,需要有通知栏,服务才不会被Android系统给关闭,也不知道有没有起到作用😂

还需要注意的是,需要声明权限

<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> 
NotifyUtil工具类代码
public class NotifyUtil {     private static String channel_id="myChannelId";     private static String channel_name="新消息";     private static String description = "新消息通知";     private static int notifyId = 0;     private static NotificationManager notificationManager;      public static void createNotificationChannel(){         if (notificationManager != null) {             return;         }         //Android8.0(API26)以上需要调用下列方法,但低版本由于支持库旧,不支持调用         if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){             int importance = NotificationManager.IMPORTANCE_HIGH;             NotificationChannel channel = new NotificationChannel(channel_id,channel_name,importance);             channel.setDescription(description);             notificationManager = (NotificationManager) ActivityUtils.getTopActivity().getSystemService(Context.NOTIFICATION_SERVICE);             notificationManager.createNotificationChannel(channel);         }else{             notificationManager = (NotificationManager) ActivityUtils.getTopActivity().getSystemService(Context.NOTIFICATION_SERVICE);         }     }      public static void sendNotification(String title,String text){         createNotificationChannel();         Notification notification = new NotificationCompat.Builder(ActivityUtils.getTopActivity(),channel_id)                 .setContentTitle(title)                 .setContentText(text)                 .setWhen(System.currentTimeMillis())                 .setSmallIcon(ResourceUtils.getMipmapIdByName("ic_launcher"))                 .setLargeIcon(BitmapFactory.decodeResource(ActivityUtils.getTopActivity().getResources(), ResourceUtils.getMipmapIdByName("ic_launcher")))                 .setPriority(NotificationCompat.PRIORITY_DEFAULT)                 .build();         notificationManager.notify(notifyId++,notification);     }      public static Notification sendNotification(Context context,String title,String text,int priority){         createNotificationChannel();         Notification notification = new NotificationCompat.Builder(context,channel_id)                 .setContentTitle(title)                 .setContentText(text)                 .setWhen(System.currentTimeMillis())                 .setSmallIcon(ResourceUtils.getMipmapIdByName("ic_launcher"))                 .setLargeIcon(BitmapFactory.decodeResource(ActivityUtils.getTopActivity().getResources(), ResourceUtils.getMipmapIdByName("ic_launcher")))                 .setPriority(priority)                 .build();         notificationManager.notify(notifyId++,notification);         return notification;     }      public static void sendNotification(String title, String text, int priority, PendingIntent pendingIntent){         createNotificationChannel();         Notification notification = new NotificationCompat.Builder(ActivityUtils.getTopActivity(),channel_id)                 .setContentTitle(title)                 .setContentText(text)                 .setWhen(System.currentTimeMillis())                 .setSmallIcon(ResourceUtils.getMipmapIdByName("ic_launcher"))                 .setLargeIcon(BitmapFactory.decodeResource(ActivityUtils.getTopActivity().getResources(), ResourceUtils.getMipmapIdByName("ic_launcher")))                 .setPriority(priority)                 .setContentIntent(pendingIntent)                 .build();         notificationManager.notify(notifyId++,notification);     } } 

2.服务

声明一个服务,然后在服务中开启一个线程,用来连接MQ,MQ的消费事件中,发送广播

//发出一条广播 String ALARM_ACTION_CODE = "OPEN_SERVICE"; Intent intent = new Intent(ALARM_ACTION_CODE); //适配8.0以上(不然没法发出广播) 显式声明组件 if (DeviceUtils.getSDKVersionCode() > Build.VERSION_CODES.O) {     intent.setComponent(new ComponentName(context, MyReceiver.class)); } intent.putExtra("text", msg); context.sendBroadcast(intent); 

之后大体上就是测试了,打开APP,然后直接返回桌面,大概1分钟后,APP就无法播放语音

而使用了上述的思路,不管是锁屏还是回到桌面(测试使用的是Android11,谷歌官方系统),都可以实现语音播放,不过未在其他系统的手机上尝试过

原本现场的设备也就是一个华为平板,而且是鸿蒙系统的

发表评论

相关文章