У меня есть собственный 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
Composable, связанный с Exoplayer, делает приложение не отвечающим ⇐ Android
Форум для тех, кто программирует под Android
-
Anonymous
1771073047
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
)
)
}
}
}
}
}
}
}
Подробнее здесь: [url]https://stackoverflow.com/questions/79889249/exoplayer-related-composable-makes-an-app-not-responsive[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия