相关文章推荐
热心的皮蛋  ·  MethodArgumentNotValid ...·  1 月前    · 
小眼睛的课本  ·  Perform an in-place ...·  11 月前    · 
奔跑的哑铃  ·  javascript - ...·  1 年前    · 
自信的橡皮擦  ·  ora-01775 ...·  1 年前    · 

1.服务是什么(Service)

Service 是一种可在后台执行长时间运行操作而不提供界面的应用组件。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。此外,组件可通过绑定到服务与之进行交互,甚至是执行进程间通信 (IPC)。例如, 服务可在后台处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序进行交互

2.前台服务(ForegroundService)是什么?

前台服务执行一些用户能注意到的操作 。例如,音频应用会使用前台服务来播放音频曲目。前台服务必须显示通知。即使用户停止与应用的交互,前台服务仍会继续运行。

最常见的表现形式就是 音乐播放服务 ,应用程序后台运行时,用户可以通过通知栏,知道当前播放内容,并进行暂停、继续、切歌等相关操作。

3.为什么用前台服务

后台运行的Service系统优先级相对较低,当系统内存不足时,在后台运行的Service就有可能被回收, 为了保持后台服务的正常运行及相关操作,可以选择将需要保持运行的Service设置为前台服务,从而使APP长时间处于后台或者关闭(进程未被清理)时,服务能够保持工作

4.前台服务使用

4.1定义前台服务

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

4.2在AndroidManifest.xml注册服务

<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异常;

4.3创建服务通知内容,例如音乐播放,蓝牙设备正在连接等

   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主要有七种层次:

  • IMPORTANCE_DEFAULT: 默认notification importance,可以在任何地方显示,有声音。
  • IMPORTANCE_HIGH:可以在任何地方显示,有声音.
  • IMPORTANCE_LOW:可以在任何地方显示,没有声音.
  • IMPORTANCE_MAX:重要程度最高,可以在任何地方显示,有声音,可以在用户当前屏幕上显示通知,可以使用full screen intents.比如来电。
  • IMPORTANCE_MIN:无声音,不会出现在状态栏中。
  • IMPORTANCE_NONE:在任何地方都不会显示,被阻塞。
  • IMPORTANCE_UNSPECIFIED:表示用户没有表示重要性的值。这个值是为了持久的首选项,并且永远不应该与实际的通知相关联。

4.4在Application或需要开启服务的地方调用

//启动服务 
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()在前台启动新服务

4.5在Application或其他地方停止服务

//停止服务
mForegroundService = Intent(this, ForegroundService::class.java);
stopService(mForegroundService)

4.6启动前台服务时创建通知

ForegroundService
override fun onCreate() {
        super.onCreate()
         //标记服务启动
        serviceIsLive = true
        val notification: Notification = createForegroundNotification()
        //将服务置于启动状态 ,NOTIFICATION_ID指的是创建的通知的ID
        startForeground(NOTIFICATION_ID, notification)

4.7停止服务,关闭通知

ForegroundService    
override fun onDestroy() {
        super.onDestroy()
        Log.d(TAG, "onDestroy")
        stopForeground(true)
        ForegroundService.serviceIsLive = false;

4.8完成整前台服务类

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及以上通知需要添加通知渠道,否则无法显示;
  • Android9.0前台服务通知需要添加<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>权限;
  • Android 8.0使用startForegroundService在前台启动新服务;

Android8.0后台执行限制
为提高设备性能,系统会限制未在前台运行的应用的某些行为。具体而言:

  • 在后台运行的应用对后台服务的访问受到限制
  • 应用无法使用其清单注册大部分隐式广播

默认情况下,这些限制仅适用于针对O的应用。不过用户可以从Settings屏幕为任意应用启用这些限制,即使应用并不是以O为目标平台。

Android8.0还对特定函数做出了如下变更:

  • 如果针对Android8.0的应用尝试在不允许创建其后台服务的情况下使用startService()函数,则该函数将引发一个IllegalStateException.
  • Context.startForegroundService()函数将启动一个前台服务。即使应用在后台运行,系统也允许其调用Context.startForegroundService().不过,应用必须在创建服务后的5秒内调用改服务的startForegroun()函数,否则将报ANR(Application Not Responding)错误。

​​​​​​Android通知栏前台服务 - 几圈年轮 - 博客园

Android8.0使用通知创建前台服务_Haienzi的博客-CSDN博客_android 创建前台服务

Foreground services  |  Android Developers

1.服务是什么(Service)Service 是一种可在后台执行长时间运行操作而不提供界面的应用组件。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。此外,组件可通过绑定到服务与之进行交互,甚至是执行进程间通信 (IPC)。例如,服务可在后台处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序进行交互。2.前台服务(ForegroundService)是什么?前台服务执行一些用户能注意到的操作。例如,音频应用会使用前台服务来播放音频曲目。前台服务必须显示通知
代码可以直接运行,实现了android平台服务前台化,并以Notification显示到右下脚。代码可以在任何版本API运行。考虑了各种版本的API情况。内部使用了发射机制。 简略说下服务前台化的好处:即提高了服务的优先级别,普通服务是默认后台运行的。当android系统发现内存不够时,极易自动killed掉你的服务。如果,改用前台则不易被killed,当然,内存极度低时同样会killed。 本代码来源于对android的apidemos的研究。
本文档主要讲解锁屏的启动流程,锁屏的灭屏上锁,锁屏的亮屏解锁逻辑。 此文档适合SystemUI的初学者,能让SystemUI初学者立刻马上接手SystemUI锁屏模块。 有助于SytemUI锁屏的开发。 SystemUI锁屏初学者 SytemUI锁屏模块的开发与应用。
IntentService具有以下特点: (1) IntentService自带一个工作线程,当我们的Service需要做一些可能会阻塞主线程的工作的时候可以考虑使用IntentService。 (2) 我们需要将要做的实际工作放入到IntentService的onHandleIntent回到方法中,当我们通过startService(intent)启动了Int...
Android前台Service 是指一个能够在Notification栏中显示通知的Service。通过前台Service,在后台运行时,用户可以看到一个通知,以此提示用户该服务正在运行。前台Service在Android系统中用于一些比较重要的服务,比如音乐播放器、即时通讯、闹钟、导航等等。在应用程序需要长时间后台运行时,可使用前台Service。 在使用前台Service时,需要在Service中创建并设置Notification通知。其中,Notification通知是用户与Service进行交互的唯一方式,当通知被点击时,可以通过Intent来启动或停止Service。 对于一些比较耗电的服务,如GPS定位、音乐播放器等,使用前台Service可以避免在后台运行时被系统杀死,从而保证服务持续稳定运行,提高用户体验。 但是需要注意,虽然前台Service可以提高进程的优先级,但是在使用时需注意不要过度使用,因为长时间占用内存、耗电量过大,也会对用户造成不良影响。因此,在使用前台Service时,需权衡其重要性和对系统资源的影响,以达到合理使用的目的。