Android 启动前台服务¶
更新日期: 2021-8-26
- 2021-8-26 创建
前台服务可以给用户提供界面上的操作。 每个前台服务都必须要在通知栏显示一个通知(notification)。用户可以感知到app的前台服务正在运行。 这个通知(notification)默认是不能移除的。服务停止后,通知会被系统移除。 当用户不需要直接操作app,app需要给用户一个状态显示的时候,可以用前台服务。
市面上的app,例如各类音乐app
本文针对Android 8(Oreo,SDK_INT 26)及以后的版本。
使用说明¶
本例会使用1个Activity和1个Service。演示如何启动前台服务,停止服务。
manifest¶
在manifest里注册ForegroundDemoAct
和ForegroundService1
。并且申请权限FOREGROUND_SERVICE
。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.rustfisher.tutorial2020">
<!-- 前台服务权限 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application ... >
<service android:name=".service.foreground.ForegroundService1" />
<activity
android:name=".service.foreground.ForegroundDemoAct"
android:launchMode="singleTop" />
</application>
</manifest>
singleTop
。是为了方便演示点击通知时候的跳转效果。
启动前台服务¶
在activity中启动服务,调用startForegroundService(Intent)
方法。
然后在service中,需要对应地使用startForeground
方法。
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.d(TAG, "onStartCommand flags:$flags, startId:$startId [$this] ${Thread.currentThread()}")
val pendingIntent: PendingIntent =
Intent(this, ForegroundDemoAct::class.java).let { notificationIntent ->
PendingIntent.getActivity(this, 0, notificationIntent, 0)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val chanId = "f-channel"
val chan = NotificationChannel(chanId, "前台服务channel",
NotificationManager.IMPORTANCE_NONE)
chan.lightColor = Color.BLUE
chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
val service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
service.createNotificationChannel(chan)
Log.d(TAG, "服务调用startForeground")
val notification: Notification =
Notification.Builder(applicationContext, chanId)
.setContentTitle("RustFisher前台服务")
.setContentText("https://an.rustfisher.com")
.setSmallIcon(R.drawable.f_zan_1)
.setContentIntent(pendingIntent)
.build()
startForeground(1, notification)
} else {
Log.d(TAG, "${Build.VERSION.SDK_INT} < O(API 26) ")
}
return super.onStartCommand(intent, flags, startId)
}
Notification
。
- PendingIntent会被分配给Notification,作为点击通知后的跳转动作
- 使用NotificationManager先创建了一个NotificationChannel
- 用Notification.Builder配置并创建一个Notification,例如配置标题,内容文字,图标等
- 启动前台服务,调用
startForeground(1, notification)
方法
在设备上会显示出一个通知(以OnePlus5为例)
点击这个通知,会跳转到ForegroundDemoAct。这是之前用PendingIntent设置的。
停止服务¶
可以用stopService
来停止服务
onDestroy
方法。
停止前台服务¶
在Service中调用stopForeground(boolean)
方法,能停止前台,但是不退出整个服务。
这个boolean表示是否取消掉前台服务的通知。false表示保留通知。
例如在Service中调用
服务变成了后台服务,并没有退出。此时对应的通知可以滑动取消掉。报错信息¶
ANR¶
在Activity中调用startForegroundService(Intent)
启动服务,但是不调用Service.startForeground()
。
一加5手机Android10运行log如下
2021-08-26 23:03:25.352 25551-25551/com.rustfisher.tutorial2020 D/rustAppUseStartService: 调用 startForegroundService 主线程信息Thread[main,5,main]
2021-08-26 23:03:25.368 25551-25551/com.rustfisher.tutorial2020 D/rustAppForeground1: onCreate Thread[main,5,main] rustfisher.com
2021-08-26 23:03:25.370 25551-25551/com.rustfisher.tutorial2020 D/rustAppForeground1: onStartCommand flags:0, startId:1 [com.rustfisher.tutorial2020.service.foreground.ForegroundService1@c77d408] Thread[main,5,main]
2021-08-26 23:03:35.375 1596-1720/? W/ActivityManager: Bringing down service while still waiting for start foreground: ServiceRecord{53d70f2 u0 com.rustfisher.tutorial2020/.service.foreground.ForegroundService1}
2021-08-26 23:03:35.382 25551-25551/com.rustfisher.tutorial2020 D/rustAppForeground1: onDestroy [com.rustfisher.tutorial2020.service.foreground.ForegroundService1@c77d408] Thread[main,5,main]
2021-08-26 23:03:52.956 1596-1720/? E/ActivityManager: ANR in com.rustfisher.tutorial2020
PID: 25551
Reason: Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{53d70f2 u0 com.rustfisher.tutorial2020/.service.foreground.ForegroundService1}
Bad notification¶
我们在ForegroundService1的方法onStartCommand
里加入startForeground
。
如果startForeground(0, noti)
的id传入0,则会报错RemoteServiceException
。
29871-29871/com.rustfisher.tutorial2020 E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.rustfisher.tutorial2020, PID: 29871
android.app.RemoteServiceException: Bad notification for startForeground
小结¶
- 通过
startForegroundService()
启动前台服务,必须在Service中有startForeground()
,否则会ANR,或者崩溃 startForeground()
中的id
不能为0,notification
不能为null- 服务可以退出前台
stopForeground
参考¶
- Service综述 https://an.rustfisher.com/android/service/service-intro/
- Android前台服务 https://developer.android.com/guide/components/foreground-services
本文也发布在
本站说明
一起在知识的海洋里呛水吧。广告内容与本站无关。如果喜欢本站内容,欢迎投喂作者,谢谢支持服务器。如有疑问和建议,欢迎在下方评论~