美文网首页
2023-11-20 Flutter Widget 更新机制-u

2023-11-20 Flutter Widget 更新机制-u

作者: 我是小胡胡分胡 | 来源:发表于2023-11-19 12:11 被阅读0次

    Flutter 页面刷新机制

    Element? updateChild(Element? child, Widget? newWidget, Object? newSlot) {
        if (newWidget == null) {
          if (child != null) {
            deactivateChild(child);
          }
          return null;
        }
    
        final Element newChild;
        if (child != null) {
          bool hasSameSuperclass = true;
    
    
          if (hasSameSuperclass && child.widget == newWidget) {
     
            if (child.slot != newSlot) {
              updateSlotForChild(child, newSlot);
            }
            newChild = child;
            
          } else if (hasSameSuperclass && Widget.canUpdate(child.widget, newWidget)) {
            if (child.slot != newSlot) {
              updateSlotForChild(child, newSlot);
            }
    
    
            child.update(newWidget);
    
            newChild = child;
          } else {
            deactivateChild(child);
    
    
     
            newChild = inflateWidget(newWidget, newSlot);
          }
        } else {
     
          newChild = inflateWidget(newWidget, newSlot);
        }
    
    
     
        final Key? key = newWidget.key;
        if (key is GlobalKey) {
     
          owner!._debugReserveGlobalKeyFor(this, newChild, key);
        }
      
    
        return newChild;
      }
    

    这段Flutter源码是关于Element类中的updateChild方法。Element是Flutter框架中用于构建和管理Widget树的基本元素:

    以下是对该方法执行流程的简要分析:

    参数检查: 方法接受三个参数,child表示当前的子元素(可以为null),newWidget表示新的Widget,newSlot表示新的槽(slot)。

    处理newWidget为null的情况: 如果newWidget为null,表示要移除当前的子元素,因此会调用deactivateChild(child)来停用当前的子元素,并返回null。

    处理newWidget不为null的情况:

    • a. 如果当前child不为null,表示存在已有的子元素。

    • b. 检查是否具有相同的父类(hasSameSuperclass),如果有,则进行进一步的比较。

    • c. 如果child.widget与newWidget相同,且child.slot与newSlot不同,则更新child的槽。

    • d. 如果child.widget与newWidget相同且槽相同,直接返回child。

    • e. 如果具有相同的父类且Widget.canUpdate(child.widget, newWidget)为true,则表示可以直接更新child的Widget。更新槽并返回child。

    canUpdate 方法实现为:

      static bool canUpdate(Widget oldWidget, Widget newWidget) {
        return oldWidget.runtimeType == newWidget.runtimeType
            && oldWidget.key == newWidget.key;
      }
    
    • f. 如果以上条件都不满足,调用deactivateChild(child)来停用当前子元素。

    • g. 调用inflateWidget(newWidget, newSlot)来创建并返回新的子元素。

    处理child为null的情况: 如果child为null,表示当前没有子元素,直接调用inflateWidget(newWidget, newSlot)来创建并返回新的子元素。

    返回结果: 返回新创建的子元素newChild。

    这段代码主要负责管理Element的子元素,根据新的Widget和槽来更新或创建子元素,并根据一定的条件判断是否需要停用当前子元素。

    继续查看inflateWidget 函数:

      Element inflateWidget(Widget newWidget, Object? newSlot) {
     
    
        try {
          final Key? key = newWidget.key;
          if (key is GlobalKey) {
            final Element? newChild = _retakeInactiveElement(key, newWidget);
            if (newChild != null) {
    
              newChild._activateWithParent(this, newSlot);
    
              final Element? updatedChild = updateChild(newChild, newWidget, newSlot);
    
              return updatedChild!;
            }
          }
    
          
          final Element newChild = newWidget.createElement();
    
          newChild.mount(this, newSlot);
    
          return newChild;
        } finally {
        
    
        }
      }
    

    在看createElement方法

    abstract class StatefulWidget extends Widget {
     
      const StatefulWidget({ super.key });
     
      @override
      StatefulElement createElement() => StatefulElement(this);
    
    }
    

    在看下StatefulElement方法:

    class StatefulElement extends ComponentElement {
    
      StatefulElement(StatefulWidget widget)
          : _state = widget.createState(),
            super(widget) {
    
        state._element = this;
    
        state._widget = widget;
     
      }
    
    }
    

    回到inflateWidget方法

     Element inflateWidget(Widget newWidget, Object? newSlot) {
     
    
        try {
          final Key? key = newWidget.key;
          if (key is GlobalKey) {
            final Element? newChild = _retakeInactiveElement(key, newWidget);
            if (newChild != null) {
     
              newChild._activateWithParent(this, newSlot);
    
              final Element? updatedChild = updateChild(newChild, newWidget, newSlot);
    
    
              return updatedChild!;
            }
          }
    
          
          final Element newChild = newWidget.createElement();
    
    
          newChild.mount(this, newSlot);
    
    
    
          return newChild;
        } finally {
        
    
        }
      }
    

    看一下 newChild.mount(this, newSlot); 的执行:

    
    abstract class ComponentElement extends Element {
    
      void mount(Element? parent, Object? newSlot) {
    
       
    
          _firstBuild();
    
        }
    
    
    
    }
    

    在看下 _firstBuild方法:

    
    class StatefulElement extends ComponentElement {
    
      void _firstBuild() {
        
     
          try {
    
            final Object? debugCheckForReturnedFuture = state.initState() as dynamic;
       
       
          } finally {
    
          }
    
    
          state.didChangeDependencies();
    
    
          super._firstBuild();
        }
      }
    
    
    }
    
    

    在这里调用了 state.initState()

    所以widget刷新中, 在inflateWidget中创建新的element ,整体的执行顺序如下:

    • createElement
    • createState
    • initState
    • didChangeDependencies
    • build

    如果statefullwidget key没变,则调用顺序如下:

    回到流程:

    Element? updateChild(Element? child, Widget? newWidget, Object? newSlot) {
        if (newWidget == null) {
          if (child != null) {
            deactivateChild(child);
          }
          return null;
        }
    
        final Element newChild;
        if (child != null) {
          bool hasSameSuperclass = true;
    
    
          if (hasSameSuperclass && child.widget == newWidget) {
     
            if (child.slot != newSlot) {
              updateSlotForChild(child, newSlot);
            }
            newChild = child;
            
          } else if (hasSameSuperclass && Widget.canUpdate(child.widget, newWidget)) {
            if (child.slot != newSlot) {
              updateSlotForChild(child, newSlot);
            }
    
    
            child.update(newWidget);
    
            newChild = child;
          } else {
            deactivateChild(child);
    
    
     
            newChild = inflateWidget(newWidget, newSlot);
          }
        } else {
     
          newChild = inflateWidget(newWidget, newSlot);
        }
    
    
     
        final Key? key = newWidget.key;
        if (key is GlobalKey) {
     
          owner!._debugReserveGlobalKeyFor(this, newChild, key);
        }
      
    
        return newChild;
      }
    

    看下 child.update(newWidget);

    class StatefulElement extends ComponentElement {
      void update(StatefulWidget newWidget) {
        super.update(newWidget);
        assert(widget == newWidget);
        final StatefulWidget oldWidget = state._widget!;
    
    
        _dirty = true;
        state._widget = widget as StatefulWidget;
    
        try {
          _debugSetAllowIgnoredCallsToMarkNeedsBuild(true);
          final Object? debugCheckForReturnedFuture = state.didUpdateWidget(oldWidget) as dynamic;
    
    
        } finally {
          _debugSetAllowIgnoredCallsToMarkNeedsBuild(false);
        }
        rebuild();
      }
    
    }
    
    

    在这一步调用的state.didUpdateWidget(oldWidget)

    rebuild();方法如下

    Element rebuild

    abstract class Element extends DiagnosticableTree implements BuildContext {
     void rebuild() {
    
     
        performRebuild();
    
      }
    
    }
    

    ComponentElement performRebuild

    
      
    abstract class ComponentElement extends Element {
    
      void performRebuild() {
    
        Widget? built;
        try {
    
    
          built = build();
    
    
    
    
        }
    
        try {
          _child = updateChild(_child, built, slot);
    
    
        } catch (e, stack) {
    
    
          _child = updateChild(null, built, slot);
        }
      }
    }
    

    StatefulElement build

      class StatefulElement extends ComponentElement {
        Widget build() => state.build(this);
    
      }
    

    如果statefullwidget key没变,则调用顺序如下:

    • didUpdateWidget
    • build

    相关文章

      网友评论

          本文标题:2023-11-20 Flutter Widget 更新机制-u

          本文链接:https://www.haomeiwen.com/subject/ohqmwdtx.html