To create a video player in Jetpack compose, I use ExoPlayer2. The problem is this - there is screen 1 on which the video player is located and screen 2. When switching from screen 1 to screen 2, the video player screen is displayed on screen 2 for about a second and only then disappears.
Tell me what could be the reason?
@Composable
internal fun ShowAboutCorpScreen() {
val state = localStateEventEffectModel.current.state
Scaffold(
topBar = {},
) { contentPadding ->
Column(
modifier = Modifier
.padding(contentPadding)
.fillMaxSize()
.background(SynergyTheme.colors.bgPrimary)
.verticalScroll(rememberScrollState()),
) {
state.aboutCorpData?.sections?.forEach {
SectionType.entries.find { a -> a.name == it.code.uppercase() }?.let { type ->
when (type) {
SectionType.DESCRIPTION -> BlockDescription(model = it)
else -> {}
}
}
}
}
}
}
@Composable
internal fun BlockDescription(model: SectionAboutModel) {
Column(
modifier = Modifier
.padding(horizontal = SynergyTheme.dimensions.x4)
.padding(top = SynergyTheme.dimensions.x6),
) {
Text(
text = model.title,
style = SynergyTheme.typography.textSemibold.copy(
fontSize = Constants.fontsize.f22,
lineHeight = Constants.fontsize.f28,
),
color = colorResource(id = UIStyleR.color.textPrimary),
)
VideoPlayer(model.video)
Text(
modifier = Modifier.padding(top = SynergyTheme.dimensions.x2_5),
text = model.text,
style = SynergyTheme.typography.text1Medium,
lineHeight = Constants.fontsize.f22,
color = colorResource(id = UIStyleR.color.textPrimary),
)
}
}
@Composable
private fun VideoPlayer(videoUrl: String) {
val context = LocalContext.current
var isPlaying by remember { mutableStateOf(false) }
val videoUri = Uri.parse(videoUrl)
val cacheDataSource = CacheDataSourceFactory().createCacheDataSource()
val exoPlayer = remember {
ExoPlayer.Builder(context).build().apply {
val mediaSource = ProgressiveMediaSource.Factory(cacheDataSource)
.createMediaSource(MediaItem.fromUri(videoUri))
setMediaSource(mediaSource)
playWhenReady = false
prepare()
}
}
LaunchedEffect(isPlaying) {
if (isPlaying) {
exoPlayer.seekToDefaultPosition()
exoPlayer.play()
} else {
exoPlayer.pause()
}
}
if (isPlaying) {
Box(
modifier = Modifier
.height(Constants.dimensions.d220)
.padding(vertical = SynergyTheme.dimensions.x2_5)
.clip(SynergyTheme.shapes.medium),
) {
ExoPlayerLifecycleOwner(exoPlayer)
}
} else {
Box {
ImageFromSource(
iconSource = IconSource.FromResource(
resourceId = R.drawable.about_synergy,
contentDescription = null,
),
modifier = Modifier
.fillMaxWidth()
.padding(vertical = SynergyTheme.dimensions.x2_5)
.clip(SynergyTheme.shapes.medium),
contentScale = ContentScale.FillWidth,
)
Image(
modifier = Modifier
.size(Constants.dimensions.d56)
.align(Alignment.Center)
.clickable { isPlaying = true },
painter = painterResource(id = R.drawable.about_play_video),
contentDescription = null,
contentScale = ContentScale.Crop,
)
}
}
}
@Composable
internal fun ExoPlayerLifecycleOwner(exoPlayer: ExoPlayer) {
val lifecycleOwner = rememberUpdatedState(LocalLifecycleOwner.current)
val context = LocalContext.current
DisposableEffect(
key1 = AndroidView(
modifier = Modifier.fillMaxSize(),
factory = {
StyledPlayerView(context).apply {
resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT
player = exoPlayer
}
},
),
effect = {
val observer = LifecycleEventObserver { _, event ->
when (event) {
Lifecycle.Event.ON_RESUME -> {
exoPlayer.play()
}
Lifecycle.Event.ON_PAUSE -> {
exoPlayer.stop()
}
else -> {}
}
}
val lifecycle = lifecycleOwner.value.lifecycle
lifecycle.addObserver(observer)
onDispose {
exoPlayer.release()
lifecycle.removeObserver(observer)
}
},
)
}
Use TextureView
for the player surface.
You can find the relevant code on how to do that in the sample: