InheritedWidget 뒷면 읽기
Inherited Widget의 역할이 어떻게 이루어졌는지 코드를 계속 이해하고 싶습니다.
Inherited Widget 소개
자세한 설명은 기사가 많으니 저쪽을 보세요.
InheritedWidget의 중요한 역할은 다음과 같습니다.
O(1)
(일정 시간)에서 액세스추적 코드의 전제 지식
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);
}
InheritedWidget 자체 설치는 위에 있습니다.업데이트SholdNotify는 InheritedWidget을 계승할 때 정의가 필요합니다.
이것을 보십시오. Inherited Widget의 역할은 단지 Inherited Element을 생성하는 것입니다.
!
ProxyWidget은 child만 있는 Widget입니다.거의 실현된 것이 없다.
abstract class ProxyElement extends ComponentElement
class InheritedElement extends ProxyElement
Inherited Element은 Proxy Element을 계승하는 Element이며, Proxy Element과 Stateful Element, Stateness Element 등이 공동으로 Component Element을 계승하고 있다.
의 방법은 필요에 따라 설명한다.
Element 트리를 만들 때
InheritedWidget을 사용하기 위해 Element 트리를 구축할 때 준비합니다.
void mount(Element? parent, Object? newSlot) {
//...
_updateInheritance();
}
Element.mount ()는 처음으로 Element을 트리에 넣을 때 부르는 방법입니다.마지막으로 Element.업데이트Inheritance()라고 합니다.
이름과 같이 InheritedWidget 정보를 업데이트하는 방법입니다. 내용은 다음과 같습니다.
Map<Type, InheritedElement>? _inheritedWidgets;
//...
void _updateInheritance() {
assert(_lifecycleState == _ElementLifecycle.active);
_inheritedWidgets = _parent?._inheritedWidgets;
}
부모의 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;
}
이곳에서 하는 일은 매우 간단하다.
키는 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;
}
간단합니다. 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;
}
앞부분도 똑같아요.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;
}
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();
}
super.업데이트를 사용하여 새 Widget을 바꿀 수 있습니다.캐시된 oldWidget을 사용한 다음 InheritedElement을 사용합니다.업데이트d(oldWidget)를 호출합니다.
void updated(InheritedWidget oldWidget) {
if (widget.updateShouldNotify(oldWidget))
super.updated(oldWidget);
}
개발자가 정의한 Inherited Widget입니다.업데이트ShouldNotify()만 보고 있는 상황에서 ProxyElement입니다.업데이트d()가 되었습니다.
void updated(covariant ProxyWidget oldWidget) {
notifyClients(oldWidget);
}
여기는 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();
}
방금 모니터링한 Element의 일람표로 제작된 Inherited Elementdependents를 사용합니다.최종 각 Element의 Element입니다.이른바 didChangeDependencies()의 명칭이다.
void didChangeDependencies() {
assert(_lifecycleState == _ElementLifecycle.active); // otherwise markNeedsBuild is a no-op
assert(_debugCheckOwnerBuildTargetExists('didChangeDependencies'));
markNeedsBuild();
}
이게 마지막이야.객체의 Element은 Element입니다.markNeedsBuild () 를 호출하면 needsBuild 로고가 세워지고 이후 파이프라인의 재구성 공정에서 데이터가 업데이트됩니다.
끝맺다
Reference
이 문제에 관하여(InheritedWidget 뒷면 읽기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/fastriver/articles/4ab4d728d748e2텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)