我正在尝试使用Jetpack Compose与ExoPlayer。
问题:
1. 当屏幕方向改变时,ExoPlayer会重新启动视频,但以前的播放仍然存在并在后台播放。例如,如果我将手机旋转两次,则会有三个声音轨道正在播放,并且最新的视频在前景中。 2. exoPlayer.duration一直是TIME_UNSET(Long.MIN_VALUE + 1),即使PlaybackState更改为Player.STATE_READY。通过使用exoPlayerState.exoPlayer.duration解决了这个问题。
版本:
Jetpack Compose版本:1.0.4(截至目前最新版本) ExoPlayer版本:2.15.1(截至目前最新版本)
代码:
以下是我的播放器可组合项及其实现。
问题:
1. 当屏幕方向改变时,ExoPlayer会重新启动视频,但以前的播放仍然存在并在后台播放。例如,如果我将手机旋转两次,则会有三个声音轨道正在播放,并且最新的视频在前景中。 2. exoPlayer.duration一直是TIME_UNSET(Long.MIN_VALUE + 1),即使PlaybackState更改为Player.STATE_READY。通过使用exoPlayerState.exoPlayer.duration解决了这个问题。
版本:
Jetpack Compose版本:1.0.4(截至目前最新版本) ExoPlayer版本:2.15.1(截至目前最新版本)
代码:
以下是我的播放器可组合项及其实现。
class ExoPlayerState(context: Context) {
val exoPlayer = SimpleExoPlayer.Builder(context).build()
val duration by mutableStateOf(exoPlayer.duration)
val bufferedPosition by mutableStateOf(exoPlayer.bufferedPosition)
var position by mutableStateOf(exoPlayer.currentPosition)
}
@Composable
fun Player(
modifier: Modifier = Modifier,
sourceUrl: String
) {
val context = LocalContext.current
val exoPlayerState by remember(context) { mutableStateOf(ExoPlayerState(context)) } // <---- Problem 1?
LaunchedEffect(sourceUrl) {
exoPlayerState.exoPlayer.addListener(object : Player.Listener {
override fun onPlaybackStateChanged(playbackState: Int) {
when (playbackState) {
Player.STATE_READY -> {
Log.d("Player", "STATE_READY- duration: ${exoPlayerState.duration}") // <----- Problem 2
}
Player.STATE_ENDED -> {}
Player.STATE_BUFFERING, Player.STATE_IDLE -> {}
}
}
})
val mediaSource = generateMediaSource(context, sourceUrl)
exoPlayerState.exoPlayer.setMediaSource(mediaSource)
exoPlayerState.exoPlayer.prepare()
}
AndroidView(factory = {
PlayerView(it).apply {
player = exoPlayerState.exoPlayer
useController = false
(player as SimpleExoPlayer).playWhenReady = true
}
})
// my custom player controller composable
PlayerOverlay(
exoPlayerState = exoPlayerState,
onValueChangeFinished = {
exoPlayerState.exoPlayer.seekTo(exoPlayerState.position)
},
modifier = modifier
)
}
private fun generateMediaSource(context: Context, videoUrl: String): MediaSource {
val mediaItem = MediaItem.Builder()
.setUri(Uri.parse(videoUrl))
.setDrmSessionForClearPeriods(true)
.build()
return DefaultMediaSourceFactory(buildDataSourceFactory(context)).createMediaSource(mediaItem)
}
private fun buildDataSourceFactory(context: Context): DataSource.Factory {
return DefaultDataSourceFactory(
context,
getDefaultHttpDataSourceFactory(context)
)
}
private fun getDefaultHttpDataSourceFactory(context: Context): HttpDataSource.Factory {
return DefaultHttpDataSource.Factory()
.setUserAgent(Util.getUserAgent(context, context.packageName))
}
我的猜测
我猜测现在已经正确保存了ExoPlayer的状态并进行了更新?
我认为创建 ExoPlayerState
并在可组合项中记住它会处理好这个问题,但显然这还不够。
顺便说一句,我的自定义拖动条逻辑运行良好。它可以将视频准确地定位到保存的位置。
onValueChangeFinished = {
exoPlayerState.exoPlayer.seekTo(exoPlayerState.position)
}