JetPack Compose `lazycolumn Takes '~ 3 до ~ 4 секунды, чтобы отразить мутации mutablestateListof`, даже если «поток» излAndroid

Форум для тех, кто программирует под Android
Ответить
Anonymous
 JetPack Compose `lazycolumn Takes '~ 3 до ~ 4 секунды, чтобы отразить мутации mutablestateListof`, даже если «поток» изл

Сообщение Anonymous »

Я переключаюсь между «графическими окнами» (еженедельно, ежемесячно…). Вверх по течению данные - это горячий поток (подумайте о комнате).
Чтобы сохранить стабильный размер списка, я рендеринг 30 фиксированных слотов: реальные элементы в первом n, заполнители в остальных. ViewModel мутирует mutablestateListof на месте; Пользовательский интерфейс показывает эти слоты в Lazycolumn .
наблюдается: журналы показывают, что ViewModel мутирует слоты сразу после того, как я нажимаю на чип, но пользовательский интерфейс показывает изменение заметно (чувствует себя замороженным, затем догоняет). Я хочу подтвердить, неверна ли моя компоновская проводка (например, элементы (count =…) vs ements (list) , обнаружение tolist () и т. Д.) или если что -то еще блокирует. необходимо). < /p>

Код: Выделить всё

    // MainActivity.kt
package com.example.minlag

import android.os.Bundle
import android.os.SystemClock
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.runtime.snapshots.SnapshotStateList
import androidx.compose.ui.Modifier
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewmodel.compose.viewModel
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.mapLatest
import kotlin.random.Random

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent { App() }
}
}

@Composable
fun App(vm: BillboardViewModel = viewModel()) {
val chartId by vm.chartId.collectAsState()
val slots = vm.slots                                   // SnapshotStateList
val listState = remember(chartId) {                     // per-chart scroll
androidx.compose.foundation.lazy.LazyListState()
}

Scaffold(
topBar = {
TopAppBar(title = { Text("MRE – 30 slots") },
actions = {
TextButton(onClick = { vm.setWindow(Window.WEEKLY) }) { Text("Weekly") }
TextButton(onClick = { vm.setWindow(Window.MONTHLY) }) { Text("Monthly") }
TextButton(onClick = { vm.setWindow(Window.QUARTERLY) }) { Text("Quarterly") }
}
)
}
) { padding ->
LazyColumn(modifier = Modifier.fillMaxSize().padding(padding), state = listState) {
items(
items = slots,
key = { it.index },
contentType = { slot -> if (slot.content is SlotContent.Real) 1 else 0 }
) { slot ->
when (val c = slot.content) {
is SlotContent.Real -> ListItem(
headlineContent = { Text("Rank ${c.item.rank}: ${c.item.title}") },
supportingContent = { Text("Artist ${c.item.artist}") }
)
SlotContent.Placeholder -> ListItem(
headlineContent = { Text("…loading…") }
)
}
Divider()
}
}
}

LaunchedEffect(slots) {
// When Compose sees slot list changes
println("UI saw slots @${SystemClock.uptimeMillis()} size=${slots.size}")
}
}

// ----------------- VM + fake domain -----------------

private const val SLOT_COUNT = 30

enum class Window { WEEKLY, MONTHLY, QUARTERLY }

data class UiItem(val id: Long, val rank: Int, val title: String, val artist: String)

sealed interface SlotContent {
data class Real(val item: UiItem) : SlotContent
data object Placeholder : SlotContent
}
data class Slot(val index: Int, val content: SlotContent)

class FakeDomain {
// Emits a "chart" (id + list) when window changes.
val selectedChart = MutableStateFlow(null)

suspend fun setWindow(w: Window) {
delay(50) // emulate DB/IO
val count = listOf(0, 7, 18, 30).random()
val items = List(count) { i ->
UiItem(id = i.toLong(), rank = i + 1, title = "${w.name} Song #$i", artist = "Artist $i")
}
selectedChart.value = Chart(id = w.ordinal.toLong(), items = items)
}
}
data class Chart(val id: Long, val items: List)

class BillboardViewModel : ViewModel() {
private val domain = FakeDomain()

private val _chartId = MutableStateFlow(null)
val chartId = _chartId

// Expose snapshot list directly (no toList())
private val _slots: SnapshotStateList = mutableStateListOf().apply {
repeat(SLOT_COUNT) { add(Slot(it, SlotContent.Placeholder)) }
}
val slots: SnapshotStateList  get() = _slots

init {
// Start with weekly
viewModelScope.launch(Dispatchers.IO) { domain.setWindow(Window.WEEKLY) }
observeCharts()
}

fun setWindow(w: Window) {
viewModelScope.launch(Dispatchers.IO) { domain.setWindow(w) }
}

private fun observeCharts() {
val bg = viewModelScope + Dispatchers.Default
domain.selectedChart
.conflate()
.mapLatest { chart ->
_chartId.value = chart?.id
// CPU work off-main
chart?.items?.take(SLOT_COUNT).orEmpty()
}
.let { flow ->
bg.launch {
flow.collect { items ->
// Commit slot mutations on main for deterministic apply
withContext(Dispatchers.Main.immediate) {
val t = SystemClock.uptimeMillis()
for (i in 0 until SLOT_COUNT) {
_slots[i] = if (i < items.size)
Slot(i, SlotContent.Real(items[i]))
else
Slot(i, SlotContent.Placeholder)
}
println("VM mutated slots @$t (count=${items.size})")
}
}
}
}
}
}

Что я спрашиваю
Является ли моя подключение правильной для немедленного отменения при мутировании Mutablestatelistof по индексу?
Есть ли платы с элементами (список). Изменения в окне? Слот совершается на main.imdiate.

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

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

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

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

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

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