我正在尝试将 Jetpack Compose 与 ExoPlayer 结合使用
exoPlayer.duration
TIME_UNSET
,
PlaybackState
始终为
Player.STATE_READY
exoPlayerState.exoPlayer.duration
修复的。Jetpack Compose 版本:1.0.4(目前最新) ExoPlayer版本:2.15.1(目前最新)
这是我的 Player Composable 及其实现
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)
}
可以通过添加来修复。
val context = LocalCotext.current
context.findActivity()?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
fun Context.findActivity(): Activity = when(this){
is Activity -> this
is ContextWrapper -> baseContext.findActivity()
else -> null
android:configChanges =“方向|屏幕大小”
只需将此行添加到清单中的活动中即可解决。
首先,您使用的是
remember
,它本身会在配置更改时被破坏。 rememberSaveable
是您想要使用的。
其次,您永远不应该在可组合项的上下文中存储如此重要的状态信息。始终建议将其存储在 ViewModel 中,以便在应用程序的整个生命周期中保留它。
你的玩家寻求起源,因为在
remember
ed值被破坏后,一个新的状态被创建并被记住。
只需将状态存储在 ViewModel 中并使用状态提升来读取和更新状态。了解更多这里