赞
踩
Service 是一种可在后台执行长时间运行操作而不提供界面的应用组件。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。此外,组件可通过绑定到服务与之进行交互,甚至是执行进程间通信 (IPC)。例如,服务可在后台处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序进行交互。
前台服务执行一些用户能注意到的操作。例如,音频应用会使用前台服务来播放音频曲目。前台服务必须显示通知。即使用户停止与应用的交互,前台服务仍会继续运行。
应用场景
最常见的表现形式就是音乐播放服务,应用程序后台运行时,用户可以通过通知栏,知道当前播放内容,并进行暂停、继续、切歌等相关操作。
后台运行的Service系统优先级相对较低,当系统内存不足时,在后台运行的Service就有可能被回收,为了保持后台服务的正常运行及相关操作,可以选择将需要保持运行的Service设置为前台服务,从而使APP长时间处于后台或者关闭(进程未被清理)时,服务能够保持工作。
- class ForegroundService : Service() {
-
- companion object{
- private const val TAG = "ForegroundService"
- }
-
- override fun onCreate() {
- super.onCreate()
- Log.d(TAG,"OnCreate")
- }
-
- override fun onBind(intent: Intent?): IBinder? {
- Log.d(TAG,"onBind")
- return null
- }
-
-
- override fun onUnbind(intent: Intent?): Boolean {
- Log.d(TAG,"onUnbind")
- return super.onUnbind(intent)
- }
-
- override fun onRebind(intent: Intent?) {
- super.onRebind(intent)
- }
-
- override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
- Log.d(TAG,"onStartCommand")
- return super.onStartCommand(intent, flags, startId)
- }
-
- override fun onDestroy() {
- super.onDestroy()
- Log.d(TAG, "onDestroy")
- }
-
- }
执行日志
2022-01-16 09:46:27.430 22461-22461/com.yifan.service D/ForegroundService: OnCreate
2022-01-16 09:46:27.430 22461-22461/com.yifan.service D/ForegroundService: onStartCommand
<service android:name=".ForegroundService" />
需要在Android 9(API级别28)或者以上使用前台服务需要请求FOREGROUND_SERVICE权限,FOREGROUND_SERVICE这个安装权限,因此系统自动授权给请求的APP;
- <manifest xmlns:android="http://schemas.android.com/apk/res/android" ...>
-
- <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
-
- <application ...>
- ...
- <service android:name=".ForegroundService" />
- </application>
- </manifest>
注意:
需要在Android 9(API级别28)或者以上使用前台服务需要请求FOREGROUND_SERVICE权限,若没有请求FOREGROUND_SERVICE权限,系统会抛出SecurityException异常;
- companion object{
- //通知ID
- private const val NOTIFICATION_ID = 1111
- //唯一的通知通道的ID
- private const val notificationChannelId = "notification_channel_id_01"
- }
-
- /**
- * 开启前台服务并发送通知
- */
- private fun startForegroundWithNotification(){
- //8.0及以上注册通知渠道
- createNotificationChannel()
- val notification: Notification = createForegroundNotification()
- //将服务置于启动状态 ,NOTIFICATION_ID指的是创建的通知的ID
- startForeground(NOTIFICATION_ID, notification)
- //发送通知到状态栏
- val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
- notificationManager.notify(NOTIFICATION_ID, notification);
- }
-
-
- /**
- * 创建通知渠道
- */
- private fun createNotificationChannel(){
- val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
-
- //Android8.0以上的系统,新建消息通道
- if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
- //用户可见的通道名称
- val channelName: String = "Foreground Service Notification"
- //通道的重要程度
- val importance: Int = NotificationManager.IMPORTANCE_HIGH
- //构建通知渠道
- val notificationChannel: NotificationChannel = NotificationChannel(notificationChannelId,
- channelName, importance)
- notificationChannel.description = "Channel description"
- //LED灯
- notificationChannel.enableLights(true)
- notificationChannel.lightColor = Color.RED
- //震动
- notificationChannel.vibrationPattern = longArrayOf(0,1000,500,1000)
- notificationChannel.enableVibration(true)
- //向系统注册通知渠道,注册后不能改变重要性以及其他通知行为
- notificationManager.createNotificationChannel(notificationChannel)
- }
- }
-
- /**
- * 创建服务通知
- */
- private fun createForegroundNotification(): Notification {
- val builder: NotificationCompat.Builder = NotificationCompat.Builder(applicationContext, notificationChannelId)
- //通知小图标
- builder.setSmallIcon(R.mipmap.ic_launcher_round)
- //通知标题
- builder.setContentTitle("苏宁窖藏")
- //通知内容
- builder.setContentText("苏宁是国内优秀的跨国企业?")
- //设置通知显示的时间
- builder.setWhen(System.currentTimeMillis())
- //设定启动的内容
- val activityIntent: Intent = Intent(this, MainActivity::class.java)
- activityIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
- val pendingIntent: PendingIntent = PendingIntent.getActivity(this,
- 1,activityIntent, PendingIntent.FLAG_UPDATE_CURRENT)
- builder.setContentIntent(pendingIntent)
- //设置通知优先级
- builder.priority = NotificationCompat.PRIORITY_DEFAULT
- //设置为进行中的通知
- builder.setOngoing(true)
-
- //创建通知并返回
- return builder.build()
- }
注意事项:
创建和管理通知渠道,从Android8.0开始,需要为发送的美中不同类型的通知创建一个渠道,如果在Android8.0及以上在未指定通知频道的情况下发送通知,通知不会显示,会记录错误;
创建通知渠道的步骤:
1)通过一个唯一的channel ID ,对用户可见的channel name,通知重要程度importance level构建一个通知渠道;
2)可选的使用setDescription()指定用户在系统设置页面看到的关于通知的相关描述;
3)通过createNotificationChannel()注册通知渠道。
- /**
- * 创建通知渠道
- */
- private fun createNotificationChannel(){
- val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
-
- //唯一的通知通道的ID
- val notificationChannelId = "notification_channel_id_01"
-
- //Android8.0以上的系统,新建消息通道
- if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
- //用户可见的通道名称
- val channelName: String = "Foreground Service Notification"
- //通道的重要程度
- val importance: Int = NotificationManager.IMPORTANCE_HIGH
- //构建通知渠道
- val notificationChannel: NotificationChannel = NotificationChannel(notificationChannelId,
- channelName, importance)
- notificationChannel.description = "Channel description"
- //LED灯
- notificationChannel.enableLights(true)
- notificationChannel.lightColor = Color.RED
- //震动
- notificationChannel.vibrationPattern = longArrayOf(0,1000,500,1000)
- notificationChannel.enableVibration(true)
- //向系统注册通知渠道,注册后不能改变重要性以及其他通知行为
- notificationManager.createNotificationChannel(notificationChannel)
- }
- }
importance level主要有七种层次:
- //启动服务
- if(!ForegroundService.Companion.serviceIsLive){
- mForegroundService = Intent(this, ForegroundService::class.java)
- mForegroundService.putExtra("Foreground", "This is a foreground service.");
- // Android 8.0使用startForegroundService在前台启动新服务
- if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
- startForegroundService(mForegroundService)
- }else{
- startService(mForegroundService)
- }
- }else{
- Toast.makeText(this, "前台服务正在运行中...", Toast.LENGTH_SHORT).show();
- }
注意
Android 8.0使用startForegroundService()在前台启动新服务
- //停止服务
- mForegroundService = Intent(this, ForegroundService::class.java);
- stopService(mForegroundService)
- ForegroundService
- override fun onCreate() {
- super.onCreate()
- //标记服务启动
- serviceIsLive = true
- val notification: Notification = createForegroundNotification()
- //将服务置于启动状态 ,NOTIFICATION_ID指的是创建的通知的ID
- startForeground(NOTIFICATION_ID, notification)
- }
- ForegroundService
- override fun onDestroy() {
- super.onDestroy()
- Log.d(TAG, "onDestroy")
- stopForeground(true)
- ForegroundService.serviceIsLive = false;
- }
- class ForegroundService : Service() {
-
- companion object{
- private const val TAG = "ForegroundService"
- var serviceIsLive: Boolean = false
- private const val NOTIFICATION_ID = 1111
- //唯一的通知通道的ID
- private const val notificationChannelId = "notification_channel_id_01"
- }
-
- override fun onCreate() {
- super.onCreate()
- Log.d(TAG,"OnCreate")
- startForegroundWithNotification()
- }
-
- override fun onBind(intent: Intent?): IBinder? {
- Log.d(TAG,"onBind")
- return null
- }
-
- override fun onUnbind(intent: Intent?): Boolean {
- Log.d(TAG,"onUnbind")
- return super.onUnbind(intent)
- }
-
- override fun onRebind(intent: Intent?) {
- super.onRebind(intent)
- }
-
- override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
- Log.d(TAG,"onStartCommand")
- //数据获取
- val data: String? = intent?.getStringExtra("Foreground") ?: ""
- Toast.makeText(this, data, Toast.LENGTH_SHORT).show()
- return super.onStartCommand(intent, flags, startId)
- }
-
- /**
- * 开启前景服务并发送通知
- */
- private fun startForegroundWithNotification(){
- //8.0及以上注册通知渠道
- createNotificationChannel()
- val notification: Notification = createForegroundNotification()
- //将服务置于启动状态 ,NOTIFICATION_ID指的是创建的通知的ID
- startForeground(NOTIFICATION_ID, notification)
- //发送通知到状态栏
- val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
- notificationManager.notify(NOTIFICATION_ID, notification);
- }
-
-
- /**
- * 创建通知渠道
- */
- private fun createNotificationChannel(){
- val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
-
- //Android8.0以上的系统,新建消息通道
- if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
- //用户可见的通道名称
- val channelName: String = "Foreground Service Notification"
- //通道的重要程度
- val importance: Int = NotificationManager.IMPORTANCE_HIGH
- //构建通知渠道
- val notificationChannel: NotificationChannel = NotificationChannel(notificationChannelId,
- channelName, importance)
- notificationChannel.description = "Channel description"
- //LED灯
- notificationChannel.enableLights(true)
- notificationChannel.lightColor = Color.RED
- //震动
- notificationChannel.vibrationPattern = longArrayOf(0,1000,500,1000)
- notificationChannel.enableVibration(true)
- //向系统注册通知渠道,注册后不能改变重要性以及其他通知行为
- notificationManager.createNotificationChannel(notificationChannel)
- }
- }
-
- /**
- * 创建服务通知
- */
- private fun createForegroundNotification(): Notification {
- val builder: NotificationCompat.Builder = NotificationCompat.Builder(applicationContext, notificationChannelId)
- //通知小图标
- builder.setSmallIcon(R.mipmap.ic_launcher_round)
- //通知标题
- builder.setContentTitle("苏宁窖藏")
- //通知内容
- builder.setContentText("苏宁是国内优秀的跨国企业?")
- //设置通知显示的时间
- builder.setWhen(System.currentTimeMillis())
- //设定启动的内容
- val activityIntent: Intent = Intent(this, MainActivity::class.java)
- activityIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
- val pendingIntent: PendingIntent = PendingIntent.getActivity(this,
- 1,activityIntent, PendingIntent.FLAG_UPDATE_CURRENT)
- builder.setContentIntent(pendingIntent)
- builder.priority = NotificationCompat.PRIORITY_DEFAULT
- //设置为进行中的通知
- builder.setOngoing(true)
- //创建通知并返回
- return builder.build()
- }
-
- override fun onDestroy() {
- super.onDestroy()
- Log.d(TAG, "onDestroy")
- stopForeground(true)
- ForegroundService.serviceIsLive = false;
- }
-
- }
Android8.0后台执行限制
为提高设备性能,系统会限制未在前台运行的应用的某些行为。具体而言:
默认情况下,这些限制仅适用于针对O的应用。不过用户可以从Settings屏幕为任意应用启用这些限制,即使应用并不是以O为目标平台。
Android8.0还对特定函数做出了如下变更:
参考:
Android通知栏前台服务 - 几圈年轮 - 博客园
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。