Composable, связанный с Exoplayer, делает приложение не отвечающимAndroid

Форум для тех, кто программирует под Android
Ответить
Anonymous
 Composable, связанный с Exoplayer, делает приложение не отвечающим

Сообщение Anonymous »

У меня есть собственный ExoPlayer на основе PlayerComponent. Из-за этого все приложение не реагирует на запросы во время воспроизведения. Я думал, что проблема в слишком частых обновлениях состояния позиции, но когда я увеличил период обновления (1 секунда), практически ничего не изменилось. Я предполагаю, что проблема может быть связана со слишком большим количеством событий, обрабатываемых в лямбда-выражении pointerInput. Также мне предложили заменить Canvas на Slider, но в моем случае это не подходит, поскольку в будущем мне придется рисовать более сложную временную шкалу. Можете ли вы мне помочь? Что оказывает наиболее существенное влияние на производительность?
@Composable
internal fun PlayerControls(
modifier: Modifier = Modifier,
isPlaying: Boolean,
position: Long,
duration: Long,
onPlay: () -> Unit,
onPause: () -> Unit,
onSeek: (Long) -> Unit,
onSeekBack: () -> Unit,
onSeekForward: () -> Unit,
isFullScreen: Boolean = false,
onFullscreen: ((Boolean) -> Unit)? = null,
) {
val coroutineScope = rememberCoroutineScope()

var isInteracting by rememberSaveable {
mutableStateOf(false)
}
val interactionSource = remember { MutableInteractionSource() }

val controlsShowDuration = 3000
var notActiveTimer by rememberSaveable { mutableIntStateOf(0) }
var controlsAlpha by rememberSaveable { mutableFloatStateOf(0f) }
val animatedControlsAlpha by animateFloatAsState(
targetValue = controlsAlpha,
animationSpec = tween(300)
)
LaunchedEffect(notActiveTimer) {
when (notActiveTimer) {
controlsShowDuration -> controlsAlpha = 1f
0 -> controlsAlpha = 0f
}
}
LaunchedEffect(isInteracting) {
if (isInteracting) {
notActiveTimer = controlsShowDuration
} else if (notActiveTimer > 0) {
delay(controlsShowDuration.toLong())
notActiveTimer = 0
}
}
ConstraintLayout(
modifier = modifier
.clickable(
interactionSource = interactionSource,
indication = null
) {}
.pointerInput(Unit) {
awaitPointerEventScope {
while (true) {
val event = awaitPointerEvent(PointerEventPass.Main)
val change = event.changes.firstOrNull() ?: continue
when {
!change.previousPressed && change.pressed -> { // Pointer down
isInteracting = true
}

change.pressed && change.positionChange() != Offset.Zero -> { // Dragging
isInteracting = true
}

change.previousPressed && !change.pressed -> { // Pointer up or Cancelled
isInteracting = false
}
}
}
}
}
) {
val (seekBack, seekForward, playBtn, seekBar) = createRefs()

var seekBackAlpha by rememberSaveable { mutableFloatStateOf(0f) }
val animatedSeekBackAlpha by animateFloatAsState(
targetValue = seekBackAlpha,
animationSpec = tween(durationMillis = 300)
)
Box(
modifier = Modifier
.graphicsLayer(alpha = animatedSeekBackAlpha)
.fillMaxHeight()
.fillMaxWidth(0.35f)
.constrainAs(seekBack) {
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
start.linkTo(parent.start)
}
.clip(createStadiumShape(Direction.Ltr))
.then(
when {
animatedSeekBackAlpha > 0 -> Modifier.shimmer(
direction = Direction.Rtl,
baseColor = Color(255f, 255f, 255f, 0.15f)
)

else -> Modifier
}
)
.combinedClickable(
onClick = {
isInteracting = true
isInteracting = false
},
onDoubleClick = {
coroutineScope.launch {
seekBackAlpha = 1f
onSeekBack()
delay(300)
seekBackAlpha = 0f
}
}
),
contentAlignment = Alignment.Center
) {
Icon(
modifier = Modifier.size(25.dp),
tint = Color(0f, 0f, 0f, 0.6f),
imageVector = Icons.Rounded.FastRewind,
contentDescription = stringResource(R.string.player_seek_backward_hint)
)
}
var seekForwardAlpha by rememberSaveable { mutableFloatStateOf(0f) }
val animatedSeekForwardAlpha by animateFloatAsState(
targetValue = seekForwardAlpha,
animationSpec = tween(durationMillis = 300)
)
Box(
modifier = Modifier
.graphicsLayer(alpha = animatedSeekForwardAlpha)
.fillMaxHeight()
.fillMaxWidth(0.35f)
.constrainAs(seekForward) {
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
end.linkTo(parent.end)
}
.clip(createStadiumShape(Direction.Rtl))
.then(
when {
animatedSeekForwardAlpha > 0 -> Modifier.shimmer(
direction = Direction.Ltr,
baseColor = Color(255f, 255f, 255f, 0.15f)
)

else -> Modifier
}
)
.combinedClickable(
onClick = {
isInteracting = true
isInteracting = false
},
onDoubleClick = {
coroutineScope.launch {
seekForwardAlpha = 1f
onSeekForward()
delay(300)
seekForwardAlpha = 0f
}
}
),
contentAlignment = Alignment.Center
) {
Icon(
modifier = Modifier.size(25.dp),
tint = Color(0f, 0f, 0f, 0.6f),
imageVector = Icons.Rounded.FastForward,
contentDescription = stringResource(R.string.player_seek_forward_hint)
)
}
if (animatedControlsAlpha > 0) {
IconButton(
modifier = Modifier
.size(40.dp)
.clip(CircleShape)
.graphicsLayer(alpha = animatedControlsAlpha)
.background(Color(255f, 255f, 255f, 0.7f))
.constrainAs(playBtn) {
centerTo(parent)
},
onClick = {
if (isPlaying) {
onPause()
} else {
onPlay()
}
}
) {
Icon(
modifier = Modifier
.size(28.dp)
.clip(CircleShape),
imageVector = when (isPlaying) {
true -> Icons.Rounded.Pause
false -> Icons.Rounded.PlayArrow
},
tint = Color(0f, 0f, 0f, 0.8f),
contentDescription = stringResource(R.string.player_main_button_hint)
)
}
if (duration >= 0) {
Column(
modifier = Modifier
.fillMaxWidth()
.graphicsLayer(alpha = animatedControlsAlpha)
.constrainAs(seekBar) {
bottom.linkTo(parent.bottom)
start.linkTo(parent.start)
end.linkTo(parent.end)
}
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(start = 15.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
val durationString = duration.formatDuration()
val positionString = position.formatDuration()
Text(
text = "$positionString / $durationString",
color = Color.White,
fontSize = 11.sp
)
if (onFullscreen != null) {
IconButton(
onClick = {
onFullscreen(!isFullScreen)
}
) {
Icon(
imageVector = when (isFullScreen) {
true -> Icons.Rounded.FullscreenExit
false -> Icons.Rounded.Fullscreen
},
contentDescription = "",
tint = Color.White
)
}
}
}
Box(
modifier = Modifier
.fillMaxWidth()
.height(35.dp)
.padding(horizontal = 15.dp)
.pointerInput(Unit) {
awaitPointerEventScope {
while (true) {
val event = awaitPointerEvent(PointerEventPass.Main)
val change = event.changes.firstOrNull() ?: continue
when {
!change.previousPressed && change.pressed -> { // Pointer down
isInteracting = true
val newProgress =
(change.position.x / size.width).coerceIn(0f..1f)
val newPosition =
(newProgress * duration).toLong()
onSeek(newPosition)
}

change.pressed && change.positionChange() != Offset.Zero -> { // Dragging
isInteracting = true
val newProgress =
(change.position.x / size.width).coerceIn(0f..1f)
val newPosition =
(newProgress * duration).toLong()
onSeek(newPosition)
}

change.previousPressed && !change.pressed -> { // Pointer up or Cancelled
isInteracting = false
}
}
}
}
}
) {
val primaryColor = MaterialTheme.colorScheme.primary
Canvas(
modifier = Modifier.matchParentSize()
) {
val barHeight = 12f
val width = size.width
val height = size.height
val progress = position.toFloat() / duration
drawRoundRect(
color = Color(200f, 200f, 200f, 0.7f),
topLeft = Offset(0f, height / 2f - barHeight * 3f),
size = Size(width, barHeight),
cornerRadius = CornerRadius(barHeight)
)
drawRoundRect(
color = primaryColor,
topLeft = Offset(0f, height / 2f - barHeight * 3f),
size = Size(width * progress, barHeight),
cornerRadius = CornerRadius(barHeight)
)
drawCircle(
color = primaryColor,
radius = 1.3f * barHeight,
center = Offset(
width * progress,
height / 2f - barHeight * 3f + barHeight / 2
)
)
}
}
}
}
}
}
}


Подробнее здесь: https://stackoverflow.com/questions/798 ... responsive
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Android»