Android Service & Foreground Service

更新日期: 2023-03-14 阅读次数: 2125 字数: 806 分类: Android

在调试一段 Android 蓝牙连接的代码时,不太明白为何建立蓝牙连接在 Foreground Service 中执行。

Service 与 Activity 的区别

  • Service 没有 UI 界面,类似一个后台服务
  • Activity 需要关联一个 UI 界面

Activity is a GUI and service is non-gui thread which can run in the background.

service 可以在后台运行,适合执行耗时操作。

A Service is an application component that can perform long-running operations in the background and does not provide a user interface. Another application component can start a service and it will continue to run in the background even if the user switches to another application. Additionally, a component can bind to a service to interact with it and even perform interprocess communication (IPC). For example, a service might handle network transactions, play music, perform file I/O, or interact with a content provider, all from the background.

但是,注意!!!service 依然跑在主线程里的,即,UI 线程,所以,要规避阻塞主线程。

Foreground Service

即, 前台服务。

Foreground services perform operations that are noticeable to the user. Foreground services show a status bar notification, to make users aware that your app is performing a task in the foreground and is consuming system resources.

比如,平时 Android 上用的网络工具,在开启时,就会有一个一直存在的 notification 通知条。 非常醒目,可以让用户一下就明白当前有个常驻在后台的服务。

从 Android 8.0 系统开始,应用的后台功能被大幅削减。现在只有当应用保持在前台可见状态的情况下,Service 才能保证稳定运行,一旦应用进入后台之后,Service 随时都有可能被系统回收。之所以做这样的改动,是为了防止许多恶意的应用程序长期在后台占用手机资源,从而导致手机变得越来越卡。当然,如果你真的非常需要长期在后台执行一些任务,可以使用前台 Service 或者 WorkManager。

也是从 Android 8 开始,不允许后台应用启动后台服务,需要使用 startForegroundService 指定为前台服务,否则系统会停止 Service 并抛出异常。

val intent = Intent(this, MyService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    startForegroundService(intent)
} else {
    startService(intent)
}

常用方法

  • onCreate()方法会在 Service 创建的时候调用
  • onStartCommand() 方法会在每次 Service 执行的时候调用 (例如,创建一次,执行多次)
  • onDestroy() 方法会在 Service 销毁的时候调用。

Manifest 配置

跟 Activity 一样,每一个 Service 都需要在 AndroidManifest.xml 文件中进行注册才能生效。

同时,从 Android 9.0 系统开始,使用前台服务必须在 AndroidManifest.xml 文件中进行权限声明才行:

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

手机中查看运行的 service 清单

在 Settings - System - Advanced - Developer options - Running services 中查看

代码示例

class MyService : Service() {
    ...
    override fun onCreate() {
        super.onCreate()
        Log.d("MyService", "onCreate executed")
        val manager = getSystemService(Context.NOTIFICATION_SERVICE) as
                NotificationManager
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel("my_service", "前台Service通知",
                    NotificationManager.IMPORTANCE_DEFAULT)
            manager.createNotificationChannel(channel)
        }
        val intent = Intent(this, MainActivity::class.java)
        val pi = PendingIntent.getActivity(this, 0, intent, 0)
        val notification = NotificationCompat.Builder(this, "my_service")
            .setContentTitle("This is content title")
            .setContentText("This is content text")
            .setSmallIcon(R.drawable.small_icon)
            .setLargeIcon(BitmapFactory.decodeResource(resources, R.drawable.large_icon))
            .setContentIntent(pi)
            .build()
        startForeground(1, notification)
    }
    ...
}

当然,这个 notification 也可以在 onStartCommand 中创建。

如果 5 秒内 startForeground 没有被调用,也会抛出异常。

关于作者 🌱

我是来自山东烟台的一名开发者,有敢兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊, 查看更多联系方式