在onStartCommand(...)
中更新数据
onBind(...)
onBind(...)
是一个更好的生命周期事件,用于启动startForeground
,而不是onCreate(...)
,因为onBind(...)
传递了一个Intent
,其中可能包含初始化Service
所需的重要数据。然而,这并非必要,因为onStartCommand(...)
会在Service
第一次创建或以后每次调用时都被调用。
onStartCommand(...)
onStartCommand(...)
中的startForeground
很重要,以便在Service
被创建后进行更新。
当在创建了Service
之后调用ContextCompat.startForegroundService(...)
时,onBind(...)
和onCreate(...)
不会被调用。因此,可以通过Intent
Bundle
将更新的数据传递到onStartCommand(...)
中,以更新Service
中的数据。
示例
我正在使用这个模式来在Coinverse加密货币新闻应用中实现PlayerNotificationManager
。
Activity / Fragment.kt
context?.bindService(
Intent(context, AudioService::class.java),
serviceConnection, Context.BIND_AUTO_CREATE)
ContextCompat.startForegroundService(
context!!,
Intent(context, AudioService::class.java).apply {
action = CONTENT_SELECTED_ACTION
putExtra(CONTENT_SELECTED_KEY, contentToPlay.content.apply {
audioUrl = uri.toString()
})
})
AudioService.kt
private var uri: Uri = Uri.parse("")
override fun onBind(intent: Intent?) =
AudioServiceBinder().apply {
player = ExoPlayerFactory.newSimpleInstance(
applicationContext,
AudioOnlyRenderersFactory(applicationContext),
DefaultTrackSelector())
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
intent?.let {
when (intent.action) {
CONTENT_SELECTED_ACTION -> it.getParcelableExtra<Content>(CONTENT_SELECTED_KEY).also { content ->
val intentUri = Uri.parse(content.audioUrl)
if (!intentUri.equals(uri)) {
uri = intentUri
player?.prepare(ProgressiveMediaSource.Factory(
DefaultDataSourceFactory(
this,
Util.getUserAgent(this, getString(app_name))))
.createMediaSource(uri))
player?.playWhenReady = true
buildNotification(intent.getParcelableExtra(CONTENT_SELECTED_KEY))
}
}
}
}
return super.onStartCommand(intent, flags, startId)
}
private fun buildNotification(content: Content): Unit? {
playerNotificationManager = PlayerNotificationManager.createWithNotificationChannel(
this,
content.title,
app_name,
if (!content.audioUrl.isNullOrEmpty()) 1 else -1,
object : PlayerNotificationManager.MediaDescriptionAdapter {
override fun createCurrentContentIntent(player: Player?) = ...
override fun getCurrentContentText(player: Player?) = ...
override fun getCurrentContentTitle(player: Player?) = ...
override fun getCurrentLargeIcon(player: Player?,
callback: PlayerNotificationManager.BitmapCallback?) = ...
},
object : PlayerNotificationManager.NotificationListener {
override fun onNotificationStarted(notificationId: Int, notification: Notification) {
startForeground(notificationId, notification)
}
override fun onNotificationCancelled(notificationId: Int) {
stopForeground(true)
stopSelf()
}
})
return playerNotificationManager.setPlayer(player)
}