原文地址:Android8.0 后台服务保活的一种思路 | Stars-One的杂货小窝
项目中有个MQ服务,需要一直连着,接收到消息会发送语音,且手机要在锁屏也要实现此功能
目前是使用广播机制实现,每次MQ收到消息,触发一次启动服务操作逻辑
在Android11版本测试成功,可实现上述功能
具体流程:
<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"/>
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); } }
声明一个服务,然后在服务中开启一个线程,用来连接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,谷歌官方系统),都可以实现语音播放,不过未在其他系统的手机上尝试过
原本现场的设备也就是一个华为平板,而且是鸿蒙系统的