ExoPlayer与Jetpack Compose - 屏幕方向更改会重新启动视频

3
我正在尝试使用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(截至目前最新版本)
代码:
以下是我的播放器可组合项及其实现。
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)
}

1
你的 bug 修复了吗?我也遇到了类似的问题。 - Ajay Singh Thakur
2个回答

1
可以通过添加来修复。
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

0

首先,您正在使用remember,它本身在配置更改时被销毁。 您应该使用rememberSaveable

其次,您永远不应将此类重要状态信息存储在Composable的上下文中。 始终建议将其存储在ViewModel中,以便在应用程序的生命周期内保留。

由于remember值的破坏,您的播放器会寻求原点,然后创建并记忆新状态。

只需将状态存储在ViewModel中并使用状态提升来读取和更新状态。 了解更多这里


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接