LazyColumn with nested LazyRows - memory issue

349 Views Asked by At

In my app there's a LazyColumn that contains nested LazyRows. I have a memory issue - when there are 30-40 rows and about 10-20 elements per row in the grid, it's possible to reach Out-of-Memory (OOM) by simply scrolling the list vertically up and down about 20 times. An item is a Card with some Boxes and texts. It seems that the resulting composable for each of the items is stored, even when the item is out of composition.

Here is a sample that demonstrates this. It shows a simple grid of 600 elements (they are just Text) and on my emulator gets to a memory usage of about 200 MB. (I use Android TV emulator with landscape, 120 elements are visible at once).

MainActivity.kt

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            LazyColumnTestTheme {
                // A surface container using the 'background' color from the theme
                Surface(color = MaterialTheme.colors.background) {
                    runTest()
                }
            }
        }
    }
}

@Composable
fun runTest() {
    var itemsState: MutableState<List<TestDataBlock>> = remember {
        mutableStateOf(listOf())
    }

    LaunchedEffect(Unit) {
        delay(1000)
        itemsState.value = MutableList<TestDataBlock>(30) { rowIndex ->
            val id = rowIndex
            TestDataBlock(id = id.toString(), data = 1)
        }
    }

    List(dataItems = itemsState.value)
}

@Preview
@Composable
fun List(
    dataItems: List<TestDataBlock> = listOf(TestDataBlock("1",1), TestDataBlock("2",2))
) {
    LazyColumn(
        modifier = Modifier
            .fillMaxSize()
    ) {
        itemsIndexed(items = dataItems,
            key = { _, item ->
                item.id
            }
        ) { _, rowItem ->
            drawElement(rowItem)
        }
    }
}

@Composable
fun drawElement(rowItem: TestDataBlock) {
    Text(text = "${rowItem.id}")
    LazyRow() {
        itemsIndexed(items = rowItem.testDataItems,
            key = { _, item ->
                item.id
            }
        ) { _, item ->
            Text(text = "${item.id }", color = Color.Black, modifier = Modifier.width(100.dp))
        }
    }
}

TestDataBlock.kt

@Immutable
data class TestDataBlock(
    val id: String,
    val data: Int,

) {
    val testDataItems: List<TestDataItem> = (0..20).toList().map{ TestDataItem(it.toString()) }
}

TestDataItem.kt

@Immutable
data class TestDataItem(
    val id: String
)
0

There are 0 best solutions below