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

博客 动态
0 168
优雅殿下
优雅殿下 2022-05-05 14:58:49
悬赏:0 积分 收藏

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,谷歌官方系统),都可以实现语音播放,不过未在其他系统的手机上尝试过

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

posted @ 2022-05-05 14:34 Stars-one 阅读(0) 评论(0) 编辑 收藏 举报
回帖
    优雅殿下

    优雅殿下 (王者 段位)

    2018 积分 (2)粉丝 (47)源码

    小小码农,大大世界

     

    温馨提示

    亦奇源码

    最新会员