InheritedWidget 뒷면 읽기

30442 단어 Fluttertech
HeritedWidget은 많은 Fluter의Widget 중에서도 상당히 특수한 종류에 속한다.오늘날 직접 사용하는 경우도 줄어들었지만 Provider와 Riverpod 등 내부에서 사용하는 것처럼 Fluter의 핵심 구조 중 하나이기도 하다.
Inherited Widget의 역할이 어떻게 이루어졌는지 코드를 계속 이해하고 싶습니다.

Inherited Widget 소개


자세한 설명은 기사가 많으니 저쪽을 보세요.
https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html
https://medium.com/flutter-jp/inherited-widget-37495200d965
https://qiita.com/agajo/items/375d5415cb79689a925c
InheritedWidget의 중요한 역할은 다음과 같습니다.
  • 로우 프로파일O(1)(일정 시간)에서 액세스
  • 자신을 감시하는 소부품에 변경 통지
  • 라고 적었다.

    추적 코드의 전제 지식

  • InheritedWidget의 일반 사용 방법
  • Element 트리의 존재
  • Inherited Widget의 구조는 Element 트리 안에서 처리되기 때문에 두 번째 이해는 어느 정도 필요하다.아래 기사를 참고하시오.
    https://zenn.dev/chooyan/books/934f823764db62/viewer/dfe2d1

    InheritedWidget 및 InheritedElement


    abstract class InheritedWidget extends ProxyWidget {
      const InheritedWidget({ Key? key, required Widget child })
        : super(key: key, child: child);
    
      
      InheritedElement createElement() => InheritedElement(this);
    
      
      bool updateShouldNotify(covariant InheritedWidget oldWidget);
    }
    
    https://github.com/flutter/flutter/blob/c860cba910319332564e1e9d470a17074c1f2dfd/packages/flutter/lib/src/widgets/framework.dart#L1684
    InheritedWidget 자체 설치는 위에 있습니다.업데이트SholdNotify는 InheritedWidget을 계승할 때 정의가 필요합니다.
    이것을 보십시오. Inherited Widget의 역할은 단지 Inherited Element을 생성하는 것입니다.
    !
    ProxyWidget은 child만 있는 Widget입니다.거의 실현된 것이 없다.
    abstract class ProxyElement extends ComponentElement
    
    class InheritedElement extends ProxyElement
    
    https://github.com/flutter/flutter/blob/c860cba910319332564e1e9d470a17074c1f2dfd/packages/flutter/lib/src/widgets/framework.dart#L5196
    https://github.com/flutter/flutter/blob/c860cba910319332564e1e9d470a17074c1f2dfd/packages/flutter/lib/src/widgets/framework.dart#L5089
    Inherited Element은 Proxy Element을 계승하는 Element이며, Proxy Element과 Stateful Element, Stateness Element 등이 공동으로 Component Element을 계승하고 있다.
    의 방법은 필요에 따라 설명한다.

    Element 트리를 만들 때


    InheritedWidget을 사용하기 위해 Element 트리를 구축할 때 준비합니다.
    void mount(Element? parent, Object? newSlot) {
      //...
      _updateInheritance();
    }
    
    https://api.flutter.dev/flutter/widgets/Element/mount.html
    Element.mount ()는 처음으로 Element을 트리에 넣을 때 부르는 방법입니다.마지막으로 Element.업데이트Inheritance()라고 합니다.
    이름과 같이 InheritedWidget 정보를 업데이트하는 방법입니다. 내용은 다음과 같습니다.
    Map<Type, InheritedElement>? _inheritedWidgets;
    //...
    void _updateInheritance() {
      assert(_lifecycleState == _ElementLifecycle.active);
      _inheritedWidgets = _parent?._inheritedWidgets;
    }
    
    https://github.com/flutter/flutter/blob/c860cba910319332564e1e9d470a17074c1f2dfd/packages/flutter/lib/src/widgets/framework.dart#L4198
    부모의 Element에서 직접 Inherited Widget의 맵을 물려받았다.그럼 이 맵은 어디에 쓰죠?
    사실 아까 Inherited Element이었어요.업데이트Inheritance()가 완료되었습니다.
    void _updateInheritance() {
      assert(_lifecycleState == _ElementLifecycle.active);
      final Map<Type, InheritedElement>? incomingWidgets = _parent?._inheritedWidgets;
      if (incomingWidgets != null)
        _inheritedWidgets = HashMap<Type, InheritedElement>.of(incomingWidgets);
      else
        _inheritedWidgets = HashMap<Type, InheritedElement>();
      _inheritedWidgets![widget.runtimeType] = this;
    }
    
    https://github.com/flutter/flutter/blob/c860cba910319332564e1e9d470a17074c1f2dfd/packages/flutter/lib/src/widgets/framework.dart#L5206
    이곳에서 하는 일은 매우 간단하다.
  • 부모님이 맵을 갖고 있을 때 복사하고 없으면 다시 만들기
  • 자체 유형을 키로 설정하고 Map에 추가
  • 이것들로부터 각자의 Element의inherited Widgets에서는 자체 위에 있는 Inherited Element이 Map 형식으로 기록됩니다.
    키는 InheritedWidget 유형입니다.따라서 트리에 같은 종류의 InheritedWidget이 여러 개 있으면 가장 가까운 것만 참조합니다.
    !
    루트 경로에 Theme 등이 정의되어 있더라도 트리의 중간에 Theme을 재정의하여 다음 Widget 참조의 Theme를 덮어쓸 수 있습니다.
    자세히 생각해 보면 inherited Widgets라는 이름 안에 있는 것은 Inherited Elements입니다. 매우 번거롭습니다.

    모니터링 액세스 없음


    context.액세스 유형을 호출하여 이전 버전의 Inherited Element에 액세스할 수 있습니다.
    먼저 BuildContext의 실제 상태는 해당 Element입니다.
    InheritedElement? getElementForInheritedWidgetOfExactType<T extends InheritedWidget>() {
      assert(_debugCheckStateIsActiveForAncestorLookup());
      final InheritedElement? ancestor = _inheritedWidgets == null ? null : _inheritedWidgets![T];
      return ancestor;
    }
    
    https://api.flutter.dev/flutter/widgets/Element/getElementForInheritedWidgetOfExactType.html
    간단합니다. Element 트리 구축 시 업데이트되었습니다.단지 inherited Widgets에서 대응하는 Element을 꺼냅니다.물론 방문 속도는 O(1), 상수 시간이다.방문만 하기 때문에 수치 변경도 감시하지 않는다.

    모니터링 액세스


    context.호출()을 통해 조상의 Inherited Widget OfExactType()에 액세스할 수 있습니다.그 Inherited Widget의 값이 바뀌었을 때 알림을 받을 수도 있습니다.
    Element.de p e n d O n I nherited Widget Of ExactType()는 다음과 같습니다.
    T? dependOnInheritedWidgetOfExactType<T extends InheritedWidget>({Object? aspect}) {
      assert(_debugCheckStateIsActiveForAncestorLookup());
      final InheritedElement? ancestor = _inheritedWidgets == null ? null : _inheritedWidgets![T];
      if (ancestor != null) {
        return dependOnInheritedElement(ancestor, aspect: aspect) as T;
      }
      _hadUnsatisfiedDependencies = true;
      return null;
    }
    
    //...
    
    InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object? aspect }) {
      //...
      ancestor.updateDependencies(this, aspect);
      return ancestor.widget;
    }
    
    https://api.flutter.dev/flutter/widgets/Element/dependOnInheritedWidgetOfExactType.html
    앞부분도 똑같아요.inherited Widgets에서 대응하는 Inherited Element을 얻었습니다.다른 것은 후반부에서 ancestor를 발견한 상황에서 Element이다.dependOn InheritedElement () 를 호출하고 있습니다.
    !
    aspect는 보다 세밀한 알림 제어를 할 수 있는 Inherited Model 같은 상급자를 위해 사용하는 Object입니다.InheritedWidget 메커니즘에서 사용되지 않습니다.
    dependOn Inherited Element에서widget을 되돌리기 전에 ancestor와 함께 하십시오.업데이트Dependencies()를 불러 자신의 Element을 건네준다.
    final Map<Element, Object?> _dependents = HashMap<Element, Object?>();
    
    void updateDependencies(Element dependent, Object? aspect) {
      setDependencies(dependent, null);
    }
    
    void setDependencies(Element dependent, Object? value) {
      _dependents[dependent] = value;
    }
    
    https://api.flutter.dev/flutter/widgets/InheritedElement/updateDependencies.html
    Inherited Element에서 "Element"이라고 부릅니다.dependents라는 맵에 저장합니다(위에서 설명한 대로 aspect는 의미가 없습니다).Inherited Element을 모니터링하는 Element이 등록되었습니다.

    InheritedWidget 업데이트 시


    어떤 이유로Widget 트리에 있는 Inherited Widget이 업데이트(교체)되고 Inherited Element 자체가 반복적으로 사용될 때Element이 나타납니다.업데이트로 인해 업데이트가 호출됩니다.
    Inherited Element은 Proxy Element이며 업데이트를 재생하고 있습니다.
    void update(ProxyWidget newWidget) {
      final ProxyWidget oldWidget = widget;
      assert(widget != null);
      assert(widget != newWidget);
      super.update(newWidget);
      assert(widget == newWidget);
      updated(oldWidget);
      _dirty = true;
      rebuild();
    }
    
    https://github.com/flutter/flutter/blob/c860cba910319332564e1e9d470a17074c1f2dfd/packages/flutter/lib/src/widgets/framework.dart#L5100
    super.업데이트를 사용하여 새 Widget을 바꿀 수 있습니다.캐시된 oldWidget을 사용한 다음 InheritedElement을 사용합니다.업데이트d(oldWidget)를 호출합니다.
    void updated(InheritedWidget oldWidget) {
      if (widget.updateShouldNotify(oldWidget))
        super.updated(oldWidget);
    }
    
    https://github.com/flutter/flutter/blob/c860cba910319332564e1e9d470a17074c1f2dfd/packages/flutter/lib/src/widgets/framework.dart#L5336
    개발자가 정의한 Inherited Widget입니다.업데이트ShouldNotify()만 보고 있는 상황에서 ProxyElement입니다.업데이트d()가 되었습니다.
    void updated(covariant ProxyWidget oldWidget) {
      notifyClients(oldWidget);
    }
    
    https://github.com/flutter/flutter/blob/c860cba910319332564e1e9d470a17074c1f2dfd/packages/flutter/lib/src/widgets/framework.dart#L5117
    여기는 Inherited Element입니다.그냥 notifyClient()라고 합니다.
    void notifyClients(InheritedWidget oldWidget) {
      assert(_debugCheckOwnerBuildTargetExists('notifyClients'));
      for (final Element dependent in _dependents.keys) {
        //...
        notifyDependent(oldWidget, dependent);
      }
    }
    
    void notifyDependent(covariant InheritedWidget oldWidget, Element dependent) {
      dependent.didChangeDependencies();
    }
    
    https://api.flutter.dev/flutter/widgets/InheritedElement/notifyClients.html
    방금 모니터링한 Element의 일람표로 제작된 Inherited Elementdependents를 사용합니다.최종 각 Element의 Element입니다.이른바 didChangeDependencies()의 명칭이다.
    void didChangeDependencies() {
      assert(_lifecycleState == _ElementLifecycle.active); // otherwise markNeedsBuild is a no-op
      assert(_debugCheckOwnerBuildTargetExists('didChangeDependencies'));
      markNeedsBuild();
    }
    
    https://api.flutter.dev/flutter/widgets/Element/didChangeDependencies.html
    이게 마지막이야.객체의 Element은 Element입니다.markNeedsBuild () 를 호출하면 needsBuild 로고가 세워지고 이후 파이프라인의 재구성 공정에서 데이터가 업데이트됩니다.
    끝맺다

    좋은 웹페이지 즐겨찾기