English 中文(简体)
Jetpack 混音器@ 稳定列表 < T> 参数重新组合
原标题:Jetpack Compose @Stable List<T> parameter recomposition
  • 时间:2021-09-10 19:38:19
  •  标签:
  • android

@ composable 函数被重新组合

  • if one the parameters is changed or
  • if one of the parameters is not @Stable/@Immutable

当通过 项时: list< Int> 作为参数, 组合总是重新组合, 不论 list 是不可更改的, 并且无法更改 。 ( list is interformation without @ Stable a注解 。 因此, 任何接受 list<T> 的可合成函数, 都因为参数总是被重新组合, 没有智能重新组合 。

如何将 List<T> 标记为稳定, 所以编译者知道列表是不可更改的, 功能不会因为它而需要重组?

我找到的唯一方式是像 Immmobliable data class ImmobleList<T> (val 项: List<T>) . Demo (当Child1 重新组合父子、 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)
    )
}
问题回答

您主要有两个选项:

  1. Use a wrapper class annotated with either @Immutable or @Stable (as you already did).
  2. Compose compiler v1.2 added support for the Kotlinx Immutable Collections library.

With Option 2 you just replace List with ImmutableList. Compose treats the collection types from the library as truly immutable and thus will not trigger unnecessary recompositions.

请注意:在撰写本报告时,图书馆仍为alpha。

我强烈建议阅读"https://medic.com/android Developmenters/jetpack-composition-stable-explicated-79c10db270c8" rel="noreferr"这篇文章 ,以便很好地了解如何拼写处理稳定性(加上如何调试稳定性问题)。

另一个办法是绕过一个 Snapshot StateList

具体地说,如果在您的 ViewModel 中使用Android codelab 中建议的支持值,你也有同样的问题。

private val _myList = mutableStateListOf(1, 2, 3)
val myList: List<Int> = _myList

使用 myList 的可合成物即使 不变也会被重新组合。 Opt 直接通过可变列表( 当然, 您应该将列表作为只读列表, 但现在编译者不会帮助您 ) 。

带有包装不可更改列表的示例 :

@Immutable
data class ImmutableList<T>(
    val items: List<T>
)

var itemsList = listOf(1, 2, 3)
var itemsImmutable = ImmutableList(itemsList)

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

    Column {
        // click forces recomposition of Parent
        Child1(state.value, onClick = { state.value = !state.value })
        ChildList(itemsListState)                   // Recomposes every time
        ChildImmutableList(itemsImmutableListState) // Does not recompose
        ChildSnapshotStateList(itemsMutableState)   // Does not recompose
    }
}

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

@Composable
fun ChildList(items: List<Int>) {
    Log.d("Test", "List Draw")
    Text(
        "List (${items.size})",
        modifier = Modifier
            .padding(8.dp)
    )
}

@Composable
fun ChildImmutableList(items: ImmutableList<Int>) {
    Log.d("Test", "ImmutableList Draw")
    Text(
        "ImmutableList (${items.items.size})",
        modifier = Modifier
            .padding(8.dp)
    )
}

@Composable
fun ChildSnapshotStateList(items: SnapshotStateList<Int>) {
    Log.d("Test", "SnapshotStateList Draw")
    Text(
        "SnapshotStateList (${items.size})",
        modifier = Modifier
            .padding(8.dp)
    )
}

因为Compose在收集类型为 List , Set /code> 和 Map 类时会假设它是不稳定的参数。 所以, 请在您的类中添加批注到 stable()

@Immutable
data class Foo(val lorem: List<String>) 

只要添加到关于将收藏包装在包装类中的解答和标记为

/**
 * List wrapper for Composable performance optimization. Uses delegation for read only list operations.
 */
@Immutable
data class ImmutableList<T>(
    val wrapped: List<T> = listOf()
) : List<T> by wrapped

然后可以使用包装纸,仿佛它就是清单本身:

val myList = ImmutableList<SomeClass>(listOf(...))
val firstValue = myList.first()
val lastValue = myList.last()
val size = myList.size

使用羊羔,你可以做到这一点

@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)
    )
}




相关问题
Android - ListView fling gesture triggers context menu

I m relatively new to Android development. I m developing an app with a ListView. I ve followed the info in #1338475 and have my app recognizing the fling gesture, but after the gesture is complete, ...

AsyncTask and error handling on Android

I m converting my code from using Handler to AsyncTask. The latter is great at what it does - asynchronous updates and handling of results in the main UI thread. What s unclear to me is how to handle ...

Android intent filter for a particular file extension?

I want to be able to download a file with a particular extension from the net, and have it passed to my application to deal with it, but I haven t been able to figure out the intent filter. The ...

Android & Web: What is the equivalent style for the web?

I am quite impressed by the workflow I follow when developing Android applications: Define a layout in an xml file and then write all the code in a code-behind style. Is there an equivalent style for ...

TiledLayer equivalent in Android [duplicate]

To draw landscapes, backgrounds with patterns etc, we used TiledLayer in J2ME. Is there an android counterpart for that. Does android provide an option to set such tiled patterns in the layout XML?

Using Repo with Msysgit

When following the Android Open Source Project instructions on installing repo for use with Git, after running the repo init command, I run into this error: /c/Users/Andrew Rabon/bin/repo: line ...

Android "single top" launch mode and onNewIntent method

I read in the Android documentation that by setting my Activity s launchMode property to singleTop OR by adding the FLAG_ACTIVITY_SINGLE_TOP flag to my Intent, that calling startActivity(intent) would ...

From Web Development to Android Development

I have pretty good skills in PHP , Mysql and Javascript for a junior developer. If I wanted to try my hand as Android Development do you think I might find it tough ? Also what new languages would I ...