Android8.0 后台服务保活的一种思路
原文地址:Android8.0 后台服务保活的一种思路 | Stars-One的杂货小窝
项目中有个MQ服务,需要一直连着,接收到消息会发送语音,且手机要在锁屏也要实现此功能
目前是使用广播机制实现,每次MQ收到消息,触发一次启动服务操作逻辑
在Android11版本测试成功,可实现上述功能
步骤
具体流程:
- 进入APP
- 开启后台服务Service
- 后台服务Service开启线程,连接MQ
- MQ的消费事件,发送广播
- 广播接收器中,处理启动服务(若服务已被关闭)和文本语音播放功能
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,谷歌官方系统),都可以实现语音播放,不过未在其他系统的手机上尝试过
原本现场的设备也就是一个华为平板,而且是鸿蒙系统的
Android8.0 后台服务保活的一种思路的更多相关文章
- Android P正式版即将到来:后台应用保活、消息推送的真正噩梦
1.前言 对于广大Android开发者来说,Android O(即Android 8.0)还没玩热,Andriod P(即Andriod 9.0)又要来了. 下图上谷歌官方公布的Android P ...
- Android 的保活的两种解决方案
原文链接:http://blog.csdn.net/pan861190079/article/details/72773549 详细的阐述了 Android 的保活的两种解决方案 —— 由panhao ...
- highchart访问一次后台服务返回多张图表数据
本文承接上一篇,我们制作动态图表的时候,往往需要的不止一张图表,如果每张图表都与服务接口做一次交互的话未免太过频繁,这无论对前后还是后台都是一种压力,本文介绍一种一次访问返回多组数据的方式来减少前台与 ...
- 【JavaService】部署Java jar为Windows后台服务
将Java jar文件部署为Windows后台服务有多种方法:Service Installer.Java service Wrapper.JavaService.exe等等.这里介绍下使用JavaS ...
- 答CsdnBlogger问-关于定时和后台服务问题
本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! 前段时间写了不少博客,在问答页面也陆续回答几十个问题,之后Csdn乙同学找到我,说要推荐我参加问答类 ...
- Android音视频通话过程中最小化成悬浮框的实现(类似Android8.0画中画效果)
关于音视频通话过程中最小化成悬浮框这个功能的实现,网络上类似的文章很多,但是好像还没看到解释的较为清晰的,这里因为项目需要实现了这样的一个功能,今天我把它记录下来,一方面为了以后用到便于自己查阅,一方 ...
- Android Services (后台服务)
一.简介 服务是可以在后台执行长时间运行的应用程序组件,它不提供用户界面. 另一个应用程序组件可以启动一个服务,并且即使用户切换到另一个应用程序,它仍然在后台运行. 另外,组件可以绑定到一个服务来与它 ...
- Android 后台应用保活、消息推送
3.针对以往Android版本的各种保活技术回顾 Android P之前为了搞定客户的投诉:“为什么微信能收到消息而你们的IM却不能?”,为了解决这个“痛点”,广大的Android开发者们只能让各种黑 ...
- .NET Core 中的通用主机和后台服务
简介 我们在做项目的时候, 往往要处理一些后台的任务. 一般是两种, 一种是不停的运行,比如消息队列的消费者.另一种是定时任务. 在.NET Framework + Windows环境里, 我们一般会 ...
随机推荐
- Redis 的持久化机制是什么?各自的优缺点?
Redis 提供两种持久化机制 RDB 和 AOF 机制: 1.RDBRedis DataBase)持久化方式: 是指用数据集快照的方式半持久化模式) 记录 redis 数据库的所有键值对,在某个时间 ...
- C++面试问题汇总
作者:勿忘心安~~链接:https://www.nowcoder.com/discuss/197611来源:牛客网 1 C++基础: (1)多态是怎么样的?写个样例? https://www.cnbl ...
- Java 中能创建 volatile 数组吗?
能,Java 中可以创建 volatile 类型数组,不过只是一个指向数组的引用,而不 是整个数组.我的意思是,如果改变引用指向的数组,将会受到 volatile 的保护, 但是如果多个线程同时改变数 ...
- 什么是 UML?
UML 是统一建模语言(Unified Modeling Language)的缩写,它发表于 1997 年,综合了当时已经存在的面向对象的建模语言.方法和过程,是一个支持模型 化和软件系统开发的图形化 ...
- 乱序数组中第k大的数(顺序统计量)
该问题是顺序统计量中十分经典的问题. 使用快排中的分区法,将第k大的数排序.若双向扫描分区加上三点中值法或绝对中值法,可以保证在 O(n) 时间里找出第k大的数. 补充:可以直接使用C++STL中的n ...
- 【freertos】007-系统节拍和系统延时管理实现细节
前言 本章节的时钟系统节拍主要分析FreeRTOS内核相关及北向接口层,南向接口层不分析. 本章节的系统延时主要分析任务系统延时实现. 原文:李柱明博客:https://www.cnblogs.com ...
- (stm32f103学习总结)—DS18B20
一. DS18B20简介 DS18B20数字温度传感器接线方便,封装后可应用于多种场合,如管道式,螺纹式,磁铁吸附式,不锈钢封装式.主要根据应用场合的不同而改变其外观.封装后的DS18B20可用于电缆 ...
- c语言实现两数交换的三种方法
实现变量的值互相交换的三种不同方法 方法一:利用第三个变量来实现数值的交换 int tmp; tmp = a; a = b; b = tmp; 此方法直观,简易.不易出错,推荐使用 方法二:利用两个变 ...
- 什么是jsp?jsp的内置对象有哪些?
这里是修真院前端小课堂,每篇分享文从 [背景介绍][知识剖析][常见问题][解决方案][编码实战][扩展思考][更多讨论][参考文献] 八个方面深度解析前端知识/技能,本篇分享的是: [什么是jsp? ...
- A小程序与B小程序相互跳转的一点记录
要点速览: A小程序和B小程序关联同一个公众号 B程序的用户授权 A小程序和B小程序的用户关联 诸葛 io 统计用户访问信息 需求:微信放开小程序互跳的 API 后,一些导流和拉新等活动可以在新的小程 ...