Key
局部key只会比较树中相同位置的widget,如children中index 为1的element不会复用到index为0的element位置,如果是children从后面添加元素,则前面的element可以复用。如果父element被重建,则子element一定也会被重建
StatelessWidget 如果canUpdate,会调用widget的build方法。
当新的widget并挂到树上时,会调用canUpdate方法,方法中有对key的比较
@immutable
abstract class Widget extends DiagnosticableTree {
const Widget({ this.key });
final Key key;
···
static bool canUpdate(Widget oldWidget, Widget newWidget) {
return oldWidget.runtimeType == newWidget.runtimeType
&& oldWidget.key == newWidget.key;
}
}
GlobalKey
GlobalKey其实就是缓存Element。缓存是通过GlobalKey类的静态Map _registry缓存的,当widget刷新的时候通过GlobalKey获取缓存的Element。
Element类中GlobalKey相关代码如下:
void mount(Element parent, dynamic newSlot) {
...
if (key is GlobalKey) {
key._register(this);
}
...
}
@mustCallSuper
void unmount() {
...
final Key key = _widget.key;
if (key is GlobalKey) {
key._unregister(this);
}
...
}
Element inflateWidget(Widget newWidget, dynamic newSlot) {
...
if (key is GlobalKey) {
final Element newChild = _retakeInactiveElement(key, newWidget);
...
}
...
return newChild;
}
Element _retakeInactiveElement(GlobalKey key, Widget ) {
...
final Element element = key._currentElement;
...
return element;
}
GlobalKey类主要代码如下:
abstract class GlobalKey<T extends State<StatefulWidget>> extends Key {
static final Map<GlobalKey, Element> _registry = <GlobalKey, Element>{};
void _register(Element element) {
_registry[this] = element;
}
}
void _unregister(Element element) {
if (_registry[this] == element)
_registry.remove(this);
}
Element get _currentElement => _registry[this];
BuildContext get currentContext => _currentElement;
Widget get currentWidget => _currentElement?.widget;
T get currentState {
...
}