首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在Jetpack中,“稳定注释”和“不变注释”意味着什么?

在Jetpack中,“稳定注释”和“不变注释”意味着什么?
EN

Stack Overflow用户
提问于 2021-07-29 12:28:09
回答 2查看 4.7K关注 0票数 24

在研究Jetpack撰写示例项目时,我看到了@Stable@Immutable注释。我一直在查看关于这些注释的Android文档GitHub,但我不明白。

据我所知,如果使用@Immutable,即使状态发生了更改,也不应该进行重新组合。然而,由于测试的结果,重新组合继续进行。

@Stable@Immutable注解在Jetpack中到底是做什么的?

EN

Stack Overflow用户

发布于 2022-11-15 06:52:10

定义

@Immutable是一个注释,用来告诉Compose这个对象是不可变的优化对象,所以如果不使用它,可能会触发不必要的重新组合。

@Stable是另一个注释,用于告诉Compose编译器该对象可能会更改,但当它更改时,将通知Compose运行时。

如果你读到这里,这可能是没有意义的。所以更多的解释..。

组合度量报告

当生成组合度量报告(https://github.com/androidx/androidx/blob/08c6116/compose/compiler/design/compiler-metrics.md)时,它会将事情标记为stableunstable,对于unstable对象,组合编译器无法判断对象是否被修改,因此它必须不加考虑地触发重新组合。下面是报告的两个片段:

代码语言:javascript
运行
复制
restartable skippable scheme("[androidx.compose.ui.UiComposable]") fun SomeClass1(
  stable modifier: Modifier? = @static Companion
)

restartable scheme("[androidx.compose.ui.UiComposable]") fun SomeClass2(
  stable modifier: Modifier? = @static Companion
  stable title: String
  unstable list: List<User>
  stable onClicked: Function1<User>, Unit>
)

需要可跳过的

SomeClass1的例子中,它被标记为skippable,因为它的所有参数都被标记为stable。对于SomeClass2,它不会被标记为skippable,因为它有一个属性list,即unstable

当它被标记为skippable时,这是一件好事,因为Compose编译器可以跳过任何可能的重新组合,并且它是更优化的。

什么时候不能被标记为可跳?

通常compose编译器足够聪明,可以推断什么是stable,什么是unstable。在组合编译器无法判断稳定性是可变对象的情况下,例如包含var属性的类。

代码语言:javascript
运行
复制
class SomeViewState {
  var isLoading: Boolean
}

另一种无法决定稳定性的情况是Collection类,如List,因为即使接口是List (看起来是不可变的),它实际上也可以是一个可变列表。示例:

代码语言:javascript
运行
复制
data class SomeViewState {
    val list: List<String>
}
@Composable
fun ShowSomething(data: SomeViewState) {
}

尽管上面的Composable接受SomeViewState,它的所有属性都是val,但它仍然是unstable。你可能想知道为什么?这是因为在使用方面,您实际上可以在MutableList中使用它,如下所示:

代码语言:javascript
运行
复制
ShowSomething(SomeViewState(mutableListOf()))

因此,编译器必须将其标记为unstable

因此,在这种情况下,我们想要实现的是让他们再次stable,所以他们是优化的。

@稳定和@不变的

有两种方法可以让它再次成为stable,它们使用@Stable@Immutable

使用@Stable,正如上面提到的,它意味着值可以更改,但是当它发生更改时,我们必须通知Compose编译器。这样做的方法是通过使用mutableStateOf()

代码语言:javascript
运行
复制
@Stable
class SomeViewState {
  var someFlag by mutableStateOf(false)
}

使用@Immutable,这意味着当您将数据传递到Composable中时,您将始终创建一个新的数据副本,在其他病房中,您承诺您的数据是不可变的。从上面的例子来看:

代码语言:javascript
运行
复制
@Immutable
data class SomeViewState {
    val list: List<String>
}
@Composable
fun ShowSomething(data: SomeViewState) {
}

在用@Immutable进行注释之后,在您的使用端,您应该确保创建一个新列表,而不是直接更改列表。

例如:

代码语言:javascript
运行
复制
class ViewModel {
    val state: SomeViewState = SomeViewState(listOf())
    fun removeLastItem() {
        val newList = state.list.toMutableList().apply {
                removeLast()
            }
        state = state.copy(
            list = newList
        )
    }
}

例:不要:

代码语言:javascript
运行
复制
class ViewModel {
    val state: SomeViewState = SomeViewState(mutableListOf())
    fun removeLastItem() {
        state.list.removeLast() // <=== you violate your promise of @Immutable!
    }
}

为了加深理解,您可以阅读以下链接:

票数 2
EN
查看全部 2 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68575936

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档