Flutter面试知识点1:Key

153 阅读3分钟

只讲结论、不讨论过程和验证

Key的作用

LocalKey: 当子 Widget 在 Widget 树中移动时,Key 保留其状态。它们可用于保留用户的滚动位置,或在修改集合时保持状态。

GlobalKey: 跨组件访问其关联的 Element, Context 和 State。

基类 Key 其默认实现是 String 类型的 ValueKey。

什么时候需要使用Key?

需要添加、删除或重新排序处于某种状态的 相同类型 的小部件集合时;

其实,这就是在大多数简单情况下,使用应用程序中的Key 您所需要知道的全部内容。

Key的运作方式。

当我们交换Children中Widget的顺序时,Flutter遍历Element树以查看骨架结构是否相同。它以父组件开头,然后移动到其子Widget数组。Element Tree检查新的Widget是否与旧的Widget的类型和Key相同。当小部件没有Key时,Flutter只检查其类型,对于类型相同的元素就无法实现交换。当子Widget 存在 Key 时,交换后,与相应的Widget的密钥不匹配。因此,Flutter会停用这些元素,将引用移动到Element树中的切片元素。从第一个不匹配的元素开始,然后,Flutter查看不匹配的子项,查找具有相应密钥的元素。它找到匹配项,并更新其对相应小部件的引用。

Key应该放在哪里?

widget子树顶部。

Key 的类型

1.LocalKey

局部唯一Key, 或者说是同级唯一Key,在同一父级元素中必须是唯一的(不同parent下是可以存在一样的Key),一般用于同级Widget间的比较和重排序。

  • ValueKey: 内部维护一个 泛型value属性,重写了==和hashCode(),如果两个ValueKey的 value属性相等,则认为两个Key相等;

  • ObjectKey:内部维护一个 Object?类型的value属性,同样重写了==和hashCode(),如果两ObjectKey的value属性指向同一对象,则认为两个Key相等;

  • UniqueKey: UniqueKey只和自己相等,其并没有重写==和hashCode方法,也没有const修饰的构造函数。当调用Element的updateChild方法时,Widget.canUpdate肯定返回false,所以如果你想让widget每次都去创建新的element而不复用old element,那么就给此widget使用UniqueKey。

2.GlobalKey

全局唯一Key,每次build都不会重建,可以长期保持组件的状态,一般用于跨组件访问其关联的element, context, 和State; 所有的GlobalKey都保存在BuildOwner类中的一个map里,此map的key为GlobalKey,此map的value则为GlobalKey关联的element。GlobalKey被要求全局唯一,其默认实现LabeledGloalKey因为其并没有重写==和hashCode方法,也不支持const构造函数,所以天然是全局唯一的。但是GlobalObjectKey不然,如果有两个或者多个地方使用到了拥有同一个Object的GlobalObjectKey,那么就不能保证其全局唯一性,造成程序出错。此时,可以继承GlobalObjectKey,实现一个private的内部类。

  • GlobalObjectKey: 特殊的GlobalKey,内部维护了一个Object属性,并实现了==和hashCode方法,通过判断runtimeType以及Object属性是否一致来判断两个GlobalObjectKey是否相等。为了保证GlobalObjectKey的全局唯一性,最佳实践是继承自GlobalObjectKey实现一个private的内部类,可以有效避免多人开发时可能造成的GlobalObjectKey冲突的问题。

  • LabeledGlobalKey: GlobalKey 的默认实现,内部没有实现==和hashCode方法,也没有const修饰的构造函数,所以肯定能保证其全局唯一性。