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环境里, 我们一般会 ...
随机推荐
- Flask-Script使用教程
Flask使用第三方脚本 一个干净的项目准备: 一个干净的Flask项目连接地址: https://pan.baidu.com/s/123TyVXOFvh5P7V8MbyMfDg 话不多说,上菜: 1 ...
- jsp技术之JSLT技术<c:if text="">判断
JSLT的c:if标签 作用:用来进行判断的 语法: <c:if test="判断条件,使用EL表达式进行判断"> 如果判断为true,这里的内容会生效:如果为fals ...
- 『忘了再学』Shell基础 — 7、Bash基本功能(多命令顺序执行)
目录 1.多命令执行符: 2.多命令执行符&& 3.多命令执行符|| 4.&&和||联合应用 Linux系统支持多条命令顺序执行,就是我可以依次输入多条命令后,统一按E ...
- SCTF 2018_Simple PHP Web
SCTF 2018_Simple PHP Web 进入环境注意观察url http://www.bmzclub.cn:23627/?f=login.php 有点像是文件读取我们尝试读一下/etc/pa ...
- Rust 中的数据布局-repr
repr(Rust) 首先,所有类型都有一个以字节为单位的对齐方式,一个类型的对齐方式指定了哪些地址可以用来存储该值.一个具有对齐方式n的值只能存储在n的倍数的地址上.所以对齐方式 2 意味着你必须存 ...
- c语言 相关小知识
软件运行与内存关系(垃圾数据) 内存是在操作系统的统一管理下使用的! 1.软件在运行前需要向操作系统申请访问存储空间,在内存空闲空间足够时,操作系统将分配一段内存空间并将外存中软件拷贝一份存入该内存空 ...
- java连接oracle数据库(转)
在做导游通项目所用到 package org.javawo.test; import java.sql.Connection; import java.sql.DriverManager; /** * ...
- Android普通工具类获取Context
在普通工具类中定义一个构造方法,类成员context,用于接收传过来的context 在activity中定义: 将context传过去. 在工具类中也可以使用SharePreferences,get ...
- Android 动态控制OptionMenu的显示与隐藏
在有些场景下,可能需要动态的显示和隐藏optionmenu,可以这样实现:如果在activity中默认实现了方法: onCreateOptionsMenu(Menu menu) 那么该OptionMe ...
- Restful-API和传统API的对比
阮一峰 RestFul-API 详解链接: http://www.ruanyifeng.com/blog/2014/05/restful_api.html 举例,传统api设计: 举例,RestFu ...