我在 Activity 的 onCreate 中启动服务,对于 Android Oreo 及以上版本使用 startForegroundService,对于较低版本则使用 startService,在服务中,我通过调用通知辅助方法在 Service 中使用 startForeground,当应用程序位于前台时,播放器可以完美工作,显示通知,但是一旦我从最近的应用程序中删除该应用程序,该服务就会被销毁。该服务应该继续作为前台服务工作,但我不知道为什么它一直停止
我尝试了一些解决方案,例如 Oreo 及以上版本的 startService 而不是 startForegroundService,我尝试了其他解决方案,最后一个解决方案是在服务被破坏后重新启动服务,但它可以工作,但并不理想。 我正在 Anroid 13 中测试该应用程序
这是我的活动
class MainActivity : ComponentActivity() {
private var isServiceRunning: Boolean = false
private fun startingService(){
if (!isServiceRunning){
var intent = Intent(this, PlaybackSessionService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
startForegroundService(intent)
}else{
startService(intent)
}
isServiceRunning = true
}
}
@OptIn(UnstableApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
startingService()
//the rest code compose Ui
这是我的PlaybackSessionService
class PlaybackSessionService: MediaSessionService() {
val mediaSession: MediaSession by inject()
val musiCoNotificationManager: MusiCoNotificationManager by inject()
@OptIn(UnstableApi::class)
override fun onCreate() {
super.onCreate()
Log.e("ks","onCreate service")
musiCoNotificationManager.startNotificationService(
mediaSession = mediaSession,
mediaSessionService = this
)
}
@OptIn(UnstableApi::class)
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.e("ks","onStartCommand service")
musiCoNotificationManager.startNotificationService(
mediaSession = mediaSession,
mediaSessionService = this
)
return super.onStartCommand(intent, flags, startId)
}
override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession? {
return mediaSession
}
override fun onTaskRemoved(rootIntent: Intent?) {
super.onTaskRemoved(rootIntent)
}
override fun onDestroy() {
super.onDestroy()
Log.e("ks","Service destroyed")
mediaSession.apply {
release()
if (player.playbackState != Player.STATE_IDLE){
player.seekTo(0)
player.playWhenReady = false
player.stop()
player.release()
}
}
}
}
这是我的通知管理器
class MusiCoNotificationManager(
private val context: Context,
private val player: ExoPlayer,
): KoinComponent {
@UnstableApi
fun startNotificationService(
mediaSessionService: MediaSessionService,
mediaSession: MediaSession
){
buildNotification(mediaSession)
startForegroundNotificationService(mediaSessionService)
}
private fun startForegroundNotificationService(mediaSessionService: MediaSessionService){
Log.e("ks","Enter startForeground fun in MusiCoNotificationManager class ")
val notification = NotificationCompat.Builder(context, MusicoApp.NOTIFICATION_CHANNEL_ID)
.setOngoing(true)
.setOnlyAlertOnce(true)
.build()
mediaSessionService.startForeground(MusicoApp.NOTIFICATION_ID,notification)
}
@UnstableApi
private fun buildNotification(mediaSession: MediaSession){
PlayerNotificationManager.Builder(
context,
MusicoApp.NOTIFICATION_ID,
MusicoApp.NOTIFICATION_CHANNEL_ID
)
.setMediaDescriptionAdapter(
MusiCoNotificationAdapter(context = context, pendingIntent = mediaSession.sessionActivity)
)
.setSmallIconResourceId(R.drawable.music_note)
.build()
.also {
it.setMediaSessionToken(mediaSession.platformToken)
it.setUseFastForwardActionInCompactView(true)
it.setUseNextActionInCompactView(true)
it.setUseRewindActionInCompactView(true)
it.setUsePreviousActionInCompactView(true)
it.setPriority(NotificationCompat.PRIORITY_DEFAULT)
it.setPlayer(player)
}
}
}
我解决了这个问题,只是我需要 MediaController 将其与 MediaSessionService 连接,并且使用 MediaController 你不需要从 Activity 启动ForegroundService,也不需要在服务内启动Foreground,你只需要 MediaController,前台通知由MediaSessionService 正如 documentation 所说,如果您愿意,您可以制作自定义的服务,但如果您自己发出通知,我不确定您是否需要将服务作为前台启动活动。
这是样本 在 onStart 的 Activity 中
override fun onStart() {
super.onStart()
val sessionToken = SessionToken(this, ComponentName(this,
PlayerSessionService::class.java))
val controllerFuture = MediaController.Builder(this,sessionToken).buildAsync()
controllerFuture.addListener({
if (controllerFuture.isDone){
controller = controllerFuture.get()
}
}, MoreExecutors.directExecutor()
)
}
就这个
注意: 你不能使用像 koin 或 dagger hilt 这样的 di 注入 MediaController 当我尝试使用 koin 注入它时遇到问题,这会冻结我的应用程序,原因是 MediaController 需要几秒钟才能初始化