带有 Jetpack Compose 的 ExoPlayer - 方向更改会重新启动视频

问题描述 投票:0回答:3

我正在尝试将 Jetpack Compose 与 ExoPlayer 结合使用

问题

  • 当方向改变时,ExoPlayer 会重新启动视频,但之前的播放仍然存在并在后台播放。例如,如果我旋转手机两次,就会播放三个音轨,最新的视频在前台
  • 即使
  • exoPlayer.duration 更改为
    TIME_UNSET
    PlaybackState
     始终为 
    Player.STATE_READY
    (Long.MIN_VALUE + 1) -> 这是通过使用
    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)
}
android android-jetpack-compose exoplayer exoplayer2.x
3个回答
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
投票

android:configChanges =“方向|屏幕大小”

只需将此行添加到清单中的活动中即可解决。


-1
投票

首先,您使用的是

remember
,它本身会在配置更改时被破坏。
rememberSaveable
是您想要使用的。

其次,您永远不应该在可组合项的上下文中存储如此重要的状态信息。始终建议将其存储在 ViewModel 中,以便在应用程序的整个生命周期中保留它。

你的玩家寻求起源,因为在

remember
ed值被破坏后,一个新的状态被创建并被记住。

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

© www.soinside.com 2019 - 2024. All rights reserved.