compose中验证某个类型是否稳定的办法
在开启Strong Skipping mode的情况下:
- 如果某个类型被视为不稳定,则在判断是否跳过重组时使用===比较
- 如果某个类型被视为稳定,则在判断是否跳过重组时,先使用===比较,如果为false,再使用equals比较
用这个办法可以验证后续内容中类型是否稳定。
稳定
编译器将一个类型视为稳定有如下3种情况
1.视为稳定的特定类型
- 所有基元值类型:Boolean、Int、Long、Float、Char 等。
- 字符串
- 所有函数类型 (lambda)
2.不使用@Stable注解时
用代码实验后发现在,不使用@Stable注解的情况下,,如果要让编译器认为这个类型是稳定的,需要满足如下2个条件:
- 所有属性(public/protected/privale)性被val修饰
- 属性指指向稳定类型
interface MyInterface {
val name: String
}
class MyInter(override val name: String) : MyInterface
MyInter会被编译器认为是稳定类型,因为name被val修饰并且指向稳定类型String。当进行这个判断时,只需要聚焦这2点,其他的什么都不用管。
官方文档里的要求不能准确的描述编译器的稳定性判断规则:
- The result of equals for two instances will forever be the same for the same two instances.
- If a public property of the type changes, Composition will be notified.
- All public property types are also stable.
第一点和编译器判断参数稳定性无关,例如:
private data class MyUnstable2(val value: String) {
override fun equals(other: Any?): Boolean {
val seed = System.currentTimeMillis()
val boolenaValue = Random(seed).nextBoolean()
return boolenaValue
}
}
对于2个确定是MyUnstable2实例,上述equals实现会导致,它们有时相等,有时不相等;显然,违反了第一点,但是编译器依然将MyUnstable2类型视为稳定的。
第三点说的不准确,不止是public的属性,protected/private的属性也需要指向稳定类型才行
private class MyUnstable3 {
protected val random = Random(0)
}
private class MyUnstable4 {
private val random = Random(0)
}
MyUnstable3/MyUnstable4会被编译器认为是不稳定类型。因为它们都属性指向了不可变类型。
第二点也和编译器判断参数稳定性无关,例如:
private data class MyUnstable2(val value: MyProp)
@Stable
private data class MyProp(var value: String)
当修改MyProp的value属性时,显然没有通知Composition,这违背了第二点,但是编译器依然将MyUnstable2视为稳定的。
3.使用@Stable注解时
根据@Stable的源码,@Stable注解可以在如下地方使用:
- 类/接口
- 函数
- 属性的get方法
- 属性
@MustBeDocumented
@Target(
AnnotationTarget.CLASS,
AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY,
)
@Retention(AnnotationRetention.BINARY)
@StableMarker
public annotation class Stable
1.类/接口
如果在接口上使用,则这个接口的实现类型就是稳定的
@Stable
interface MyInterface {
var name: String
}
// 1.MyInter被编译器认为是稳定类型
class MyInter(override var name: String) : MyInterface {
override fun equals(other: Any?): Boolean {
println("my inter equals function: $name")
return super.equals(other)
}
}
// 2.MyInterface2被编译器认为是稳定类型
interface MyInterface2 :MyInterface
interface MyInterface2 :MyInterface
// 3.face2对应的匿名类型实现了,所以这个匿名类型也被认为是稳定的
val face2 = object : MyInterface2 {
override var name: String = "ggg"
override fun equals(other: Any?): Boolean {
println("run MyInterface2 equals method!")
return super.equals(other)
}
}