将 exoplayer 从服务绑定到 activity 不起作用?
Binding exoplayer from service to activity not working?
以下是我的服务class
class LocalAudioService : Service() {
var player: SimpleExoPlayer? = null
private var playerNotificationManager: PlayerNotificationManager? = null
private var mediaSession: MediaSessionCompat? = null
private var mediaSessionConnector: MediaSessionConnector? = null
private var allInOneApplication: AllInOneApplication? = null
private val binder = LocalBinder()
override fun onDestroy() {
mediaSession?.release()
mediaSessionConnector?.setPlayer(null, null)
playerNotificationManager?.setPlayer(null)
player?.release()
player = null
super.onDestroy()
}
override fun onBind(p0: Intent?): IBinder? {
return binder
}
fun getPlayerInstance(): SimpleExoPlayer? {
if (player == null) {
startPlayer()
}
return player
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if(player == null){
startPlayer()
}
return START_STICKY
}
private fun startPlayer(){
val videoTrackSelectionFactory = AdaptiveTrackSelection.Factory()
val trackSelector = DefaultTrackSelector(this, videoTrackSelectionFactory)
allInOneApplication = AllInOneApplication.getInstance()
val renderersFactory = (application as AllInOneApplication).buildRenderersFactory(false)
player =
SimpleExoPlayer.Builder(this, renderersFactory).setTrackSelector(trackSelector).build()
val dataSourceFactory = DefaultDataSourceFactory(
this,
Util.getUserAgent(this, getString(R.string.app_name))
)
// val cacheDataSourceFactory = CacheDataSourceFactory(
// DownloadUtil.getCache(this),
// dataSourceFactory,
// CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR
// )
val concatenatingMediaSource = ConcatenatingMediaSource()
allInOneApplication?.localAudios?.map {
val mediaSource = ProgressiveMediaSource.Factory(dataSourceFactory)
.createMediaSource(it?.audioUri)
concatenatingMediaSource.addMediaSource(mediaSource)
}
player?.prepare(concatenatingMediaSource)
player?.playWhenReady = true
playerNotificationManager = PlayerNotificationManager.createWithNotificationChannel(
this,
AUDIO_CHANNEL_ID,
R.string.audio_channel_name,
R.string.audio_channel_name,
NOTIFICATION_ID,
object : MediaDescriptionAdapter {
override fun createCurrentContentIntent(player: Player): PendingIntent? {
val intent = Intent(this@LocalAudioService, LocalAudioPlayer::class.java)
return PendingIntent.getActivity(
this@LocalAudioService,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT
)
}
override fun getCurrentContentText(player: Player): CharSequence? {
return allInOneApplication?.localAudios?.get(player.currentWindowIndex)?.title
}
override fun getCurrentContentTitle(player: Player): CharSequence {
return allInOneApplication?.localAudios?.get(player.currentWindowIndex)?.title.toString()
}
override fun getCurrentLargeIcon(
player: Player,
callback: PlayerNotificationManager.BitmapCallback
): Bitmap? {
return BitmapFactory.decodeResource(resources, R.drawable.audio)
}
}, object : PlayerNotificationManager.NotificationListener {
override fun onNotificationPosted(
notificationId: Int,
notification: Notification,
ongoing: Boolean
) {
startForeground(notificationId, notification)
}
override fun onNotificationCancelled(
notificationId: Int,
dismissedByUser: Boolean
) {
stopSelf()
}
}
)
playerNotificationManager?.setPlayer(player)
mediaSession = MediaSessionCompat(this, MEDIA_SESSION_TAG)
mediaSession?.isActive = true
mediaSession?.sessionToken?.let { playerNotificationManager?.setMediaSessionToken(it) }
mediaSessionConnector = MediaSessionConnector(mediaSession)
mediaSessionConnector?.setQueueNavigator(object : TimelineQueueNavigator(mediaSession) {
override fun getMediaDescription(
player: Player?,
windowIndex: Int
): MediaDescriptionCompat? {
return allInOneApplication?.getMediaDescription(
this@LocalAudioService,
allInOneApplication?.localAudios?.get(windowIndex)
)
}
})
mediaSessionConnector?.setPlayer(player, null)
}
inner class LocalBinder : Binder() {
val service: LocalAudioService
get() = this@LocalAudioService
}
}
以下是我的Activityclass
class LocalAudioPlayer : AppCompatActivity() {
private var localAudioService: LocalAudioService? = null
private var mBound = false
private val mConnection: ServiceConnection = object : ServiceConnection {
override fun onServiceConnected(componentName: ComponentName, iBinder: IBinder) {
val binder: LocalAudioService.LocalBinder = iBinder as LocalAudioService.LocalBinder
localAudioService = binder.service
mBound = true
initializePlayer()
}
override fun onServiceDisconnected(componentName: ComponentName) {
mBound = false
}
}
private fun initializePlayer() {
if (mBound) {
val player: SimpleExoPlayer? = localAudioService?.getPlayerInstance()
exoplayer_local_audio_player.player = player
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_local_audio_player)
Intent(this,LocalAudioService::class.java).also {
Util.startForegroundService(this,it)
exoplayer_local_audio_player.useController = true
exoplayer_local_audio_player.showController()
exoplayer_local_audio_player.controllerAutoShow = true
exoplayer_local_audio_player.controllerHideOnTouch = false
}
}
override fun onStart() {
super.onStart()
bindService(intent,mConnection, Context.BIND_AUTO_CREATE)
initializePlayer()
//TODO do any UI setup
}
override fun onStop() {
unbindService(mConnection)
mBound = false
super.onStop()
}
}
我试过回答这个问题但是鞋底不适合我
bindService(intent,mConnection, Context.BIND_AUTO_CREATE)
此处意图为空。确保你得到正确的并且非空 intent.It 应该像参考示例
中那样被全局声明
intent = new Intent(this, AudioPlayerService.class);
这里的意图是全局声明的。
试试这个:
override fun onStart() {
super.onStart()
Intent(this, LocalAudioService::class.java).also { intent ->
bindService(intent, mConnection, Context.BIND_AUTO_CREATE)
}
}
initializePlayer()
不应该在这里调用。此时 Service 还没有绑定。当服务绑定时,它会在 onServiceConnected 回调中调用。
以下是我的服务class
class LocalAudioService : Service() {
var player: SimpleExoPlayer? = null
private var playerNotificationManager: PlayerNotificationManager? = null
private var mediaSession: MediaSessionCompat? = null
private var mediaSessionConnector: MediaSessionConnector? = null
private var allInOneApplication: AllInOneApplication? = null
private val binder = LocalBinder()
override fun onDestroy() {
mediaSession?.release()
mediaSessionConnector?.setPlayer(null, null)
playerNotificationManager?.setPlayer(null)
player?.release()
player = null
super.onDestroy()
}
override fun onBind(p0: Intent?): IBinder? {
return binder
}
fun getPlayerInstance(): SimpleExoPlayer? {
if (player == null) {
startPlayer()
}
return player
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if(player == null){
startPlayer()
}
return START_STICKY
}
private fun startPlayer(){
val videoTrackSelectionFactory = AdaptiveTrackSelection.Factory()
val trackSelector = DefaultTrackSelector(this, videoTrackSelectionFactory)
allInOneApplication = AllInOneApplication.getInstance()
val renderersFactory = (application as AllInOneApplication).buildRenderersFactory(false)
player =
SimpleExoPlayer.Builder(this, renderersFactory).setTrackSelector(trackSelector).build()
val dataSourceFactory = DefaultDataSourceFactory(
this,
Util.getUserAgent(this, getString(R.string.app_name))
)
// val cacheDataSourceFactory = CacheDataSourceFactory(
// DownloadUtil.getCache(this),
// dataSourceFactory,
// CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR
// )
val concatenatingMediaSource = ConcatenatingMediaSource()
allInOneApplication?.localAudios?.map {
val mediaSource = ProgressiveMediaSource.Factory(dataSourceFactory)
.createMediaSource(it?.audioUri)
concatenatingMediaSource.addMediaSource(mediaSource)
}
player?.prepare(concatenatingMediaSource)
player?.playWhenReady = true
playerNotificationManager = PlayerNotificationManager.createWithNotificationChannel(
this,
AUDIO_CHANNEL_ID,
R.string.audio_channel_name,
R.string.audio_channel_name,
NOTIFICATION_ID,
object : MediaDescriptionAdapter {
override fun createCurrentContentIntent(player: Player): PendingIntent? {
val intent = Intent(this@LocalAudioService, LocalAudioPlayer::class.java)
return PendingIntent.getActivity(
this@LocalAudioService,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT
)
}
override fun getCurrentContentText(player: Player): CharSequence? {
return allInOneApplication?.localAudios?.get(player.currentWindowIndex)?.title
}
override fun getCurrentContentTitle(player: Player): CharSequence {
return allInOneApplication?.localAudios?.get(player.currentWindowIndex)?.title.toString()
}
override fun getCurrentLargeIcon(
player: Player,
callback: PlayerNotificationManager.BitmapCallback
): Bitmap? {
return BitmapFactory.decodeResource(resources, R.drawable.audio)
}
}, object : PlayerNotificationManager.NotificationListener {
override fun onNotificationPosted(
notificationId: Int,
notification: Notification,
ongoing: Boolean
) {
startForeground(notificationId, notification)
}
override fun onNotificationCancelled(
notificationId: Int,
dismissedByUser: Boolean
) {
stopSelf()
}
}
)
playerNotificationManager?.setPlayer(player)
mediaSession = MediaSessionCompat(this, MEDIA_SESSION_TAG)
mediaSession?.isActive = true
mediaSession?.sessionToken?.let { playerNotificationManager?.setMediaSessionToken(it) }
mediaSessionConnector = MediaSessionConnector(mediaSession)
mediaSessionConnector?.setQueueNavigator(object : TimelineQueueNavigator(mediaSession) {
override fun getMediaDescription(
player: Player?,
windowIndex: Int
): MediaDescriptionCompat? {
return allInOneApplication?.getMediaDescription(
this@LocalAudioService,
allInOneApplication?.localAudios?.get(windowIndex)
)
}
})
mediaSessionConnector?.setPlayer(player, null)
}
inner class LocalBinder : Binder() {
val service: LocalAudioService
get() = this@LocalAudioService
}
}
以下是我的Activityclass
class LocalAudioPlayer : AppCompatActivity() {
private var localAudioService: LocalAudioService? = null
private var mBound = false
private val mConnection: ServiceConnection = object : ServiceConnection {
override fun onServiceConnected(componentName: ComponentName, iBinder: IBinder) {
val binder: LocalAudioService.LocalBinder = iBinder as LocalAudioService.LocalBinder
localAudioService = binder.service
mBound = true
initializePlayer()
}
override fun onServiceDisconnected(componentName: ComponentName) {
mBound = false
}
}
private fun initializePlayer() {
if (mBound) {
val player: SimpleExoPlayer? = localAudioService?.getPlayerInstance()
exoplayer_local_audio_player.player = player
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_local_audio_player)
Intent(this,LocalAudioService::class.java).also {
Util.startForegroundService(this,it)
exoplayer_local_audio_player.useController = true
exoplayer_local_audio_player.showController()
exoplayer_local_audio_player.controllerAutoShow = true
exoplayer_local_audio_player.controllerHideOnTouch = false
}
}
override fun onStart() {
super.onStart()
bindService(intent,mConnection, Context.BIND_AUTO_CREATE)
initializePlayer()
//TODO do any UI setup
}
override fun onStop() {
unbindService(mConnection)
mBound = false
super.onStop()
}
}
我试过回答这个问题
bindService(intent,mConnection, Context.BIND_AUTO_CREATE)
此处意图为空。确保你得到正确的并且非空 intent.It 应该像参考示例
中那样被全局声明 intent = new Intent(this, AudioPlayerService.class);
这里的意图是全局声明的。
试试这个:
override fun onStart() {
super.onStart()
Intent(this, LocalAudioService::class.java).also { intent ->
bindService(intent, mConnection, Context.BIND_AUTO_CREATE)
}
}
initializePlayer()
不应该在这里调用。此时 Service 还没有绑定。当服务绑定时,它会在 onServiceConnected 回调中调用。