Jetpack Compose @Stable List<T> 参数重组

Jem*_*rov 12 android android-jetpack-compose compose-recomposition

@Composable 函数被重构

  • 如果参数发生变化或者
  • 如果参数之一不是@Stable/@Immutable

items: List<Int>作为参数传递时,compose 总是重新组合,无论是否List是不可变的且无法更改。(List是没有@Stable注解的接口)。因此,任何接受List<T>参数的可组合函数总是会被重组,而不是智能重组。

如何标记List<T>为稳定,以便编译器知道 List 是不可变的并且函数永远不需要因此而重新组合?

我发现的唯一方法就是像这样包裹@Immutable data class ImmutableList<T>(val items: List<T>)。演示(当 Child1 重组 Parent 时,具有相同 List 的 Child2 也会被重组)

class TestActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            ComposeBasicsTheme {
                Parent()
            }
        }
    }
}

@Composable
fun Parent() {
    Log.d("Test", "Parent Draw")
    val state = remember { mutableStateOf(false) }
    val items = remember { listOf(1, 2, 3) }

    Column {
        // click forces recomposition of Parent
        Child1(value = state.value,
            onClick = { state.value = !state.value })

        //
        Child2(items)
    }
}

@Composable
fun Child1(
    value: Boolean,
    onClick: () -> Unit
) {
    Log.d("Test", "Child1 Draw")
    Text(
        "Child1 ($value): Click to recompose Parent",
        modifier = Modifier
            .clickable { onClick() }
            .padding(8.dp)
    )
}

@Composable
fun Child2(items: List<Int>) {
    Log.d("Test", "Child2 Draw")
    Text(
        "Child 2 (${items.size})",
        modifier = Modifier
            .padding(8.dp)
    )
}
Run Code Online (Sandbox Code Playgroud)

小智 -2

使用 lambda,你可以做到这一点

@Composable
fun Parent() {
    Log.d("Test", "Parent Draw")
    val state = remember { mutableStateOf(false) }
    val items = remember { listOf(1, 2, 3) }
    val getItems = remember(items) {
        {
            items
        }
    }

    Column {
        // click forces recomposition of Parent
        Child1(value = state.value,
            onClick = { state.value = !state.value })

        //
        Child2(items)
        Child3(getItems)
    }
}

@Composable
fun Child3(items: () -> List<Int>) {
    Log.d("Test", "Child3 Draw")
    Text(
        "Child 3 (${items().size})",
        modifier = Modifier
            .padding(8.dp)
    )
}
Run Code Online (Sandbox Code Playgroud)