flutter GlobalKey、Key

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 {
   ...
  }

推荐阅读更多精彩内容