在调试一段 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 聊聊, 查看更多联系方式