1. Flutter 从runApp开始

167 阅读2分钟

1. 简介

让我们从 main开始,一步一步查看一下runApp 到底经历了什么

import 'package:flutter/material.dart';

void main() {
  runApp(const MyAPP2());
}

class MyAPP2 extends StatelessWidget {
  const MyAPP2({super.key});

  @override
  Widget build(BuildContext context) {
    return Padding(padding: EdgeInsets.all(0));
  }

  @override
  StatelessElement createElement() {
    // return super.createElement();
    var element = MyApp2Element(this);
    return element;
  }
}

class MyApp2Element extends StatelessElement {
  MyApp2Element(super.widget);
  @override
  void mount(Element? parent, Object? newSlot) {
    super.mount(parent, newSlot);
  }
}

2. runApp(const MyAPP2())

void runApp(Widget app) {
  
  // 1.获取一个 WidgetsFlutterBinding 的单例
  WidgetsFlutterBinding.ensureInitialized()
  // 2. 
    ..scheduleAttachRootWidget(app)
  // 3. 初始化帧  
    ..scheduleWarmUpFrame();
}

2.1 往下我们看看 scheduleAttachRootWidget

@protected
  void scheduleAttachRootWidget(Widget rootWidget) {
    // 主要是添加一个任务
    Timer.run(() {
      attachRootWidget(rootWidget);
    });
  }

2.2 进入 attachRootWidget(rootWidget);


 void attachRootWidget(Widget rootWidget) {
    final bool isBootstrapFrame = renderViewElement == null;
    _readyToProduceFrames = true;
    
    // 2.2.1  RenderObjectToWidgetAdapter
    _renderViewElement = RenderObjectToWidgetAdapter<RenderBox>(
      // 2.2.2 初始化  WidgetsFlutterBinding => BindingBase => initInstances() => RenderBinding.initInstances() => 
      // renderView = RenderView(configuration: createViewConfiguration(), window: window); 拿到renderView
      container: renderView,
      debugShortDescription: '[root]',
      // 这个Widget 就是我们的MyApp2
      child: rootWidget, 
    )
    //  _buildOwner = BuildOwner();
    .attachToRenderTree(buildOwner!, renderViewElement as RenderObjectToWidgetElement<RenderBox>?);
    if (isBootstrapFrame) {
      SchedulerBinding.instance.ensureVisualUpdate();
    }
  }

image.png

3. 接下来我们去分析一下 element.mount

进入 RenderObjectToWidgetElement

3.1 先看看 RenderObjectToWidgetElement的 mount 和 super.mount

// 1.RenderObjectToWidgetElement
void mount(Element? parent, Object? newSlot) {
    super.mount(parent, newSlot);
    
    /**
    和 componentElement 中的 _firstBuild(StatefulElement会重载这个方法)  => rebuild => performBuild => updateChild
    最终都会调用到  updateChild
  */
    
    _rebuild();
  }
  
 // 2. RootRenderObjectElement
 @override
  void mount(Element? parent, Object? newSlot) {
    // Root elements should never have parents.
   
    super.mount(parent, newSlot);
  }
  
  //3. RenderObjectElement
  @override
  void mount(Element? parent, Object? newSlot) {
    super.mount(parent, newSlot);
     
     // 创建RenderObjcet
    _renderObject = (widget as RenderObjectWidget).createRenderObject(this);
     
     
    attachRenderObject(newSlot);
     
    super.performRebuild(); // clears the "dirty" flag
  }
  
  //4. Element
  void mount(Element? parent, Object? newSlot) {
     
    _parent = parent;
    _slot = newSlot;
    _lifecycleState = _ElementLifecycle.active;
    _depth = _parent != null ? _parent!.depth + 1 : 1;
    if (parent != null) {
      // Only assign ownership if the parent is non-null. If parent is null
      // (the root node), the owner should have already been assigned.
      // See RootRenderObjectElement.assignOwner().
      _owner = parent.owner;
    }
    
    final Key? key = widget.key;
    if (key is GlobalKey) {
      //  RootRenderObjectElement.assignOwner()  => 说明是从根传递过来的
      owner!._registerGlobalKey(key, this);
    }
    //更新子的Inherited:  _inheritedWidgets = _parent?._inheritedWidgets;
    _updateInheritance();
    // 这里是通知 _notificationTree = _parent?._notificationTree;
    attachNotificationTree();
  }
  
  

3.1 接着看RenderObjectToWidgetElement 的 _rebuild();


// 1. RenderObjectToWidgetElement
void _rebuild() {
   
   // _rootChildSlot : 其实就是一个静态的 Object()对象
   // widget as RenderObjectToWidgetAdapter<T>).child 就是 我们自定义的 MyAPP2
   // 
   _child = updateChild(_child, (widget as RenderObjectToWidgetAdapter<T>).child, _rootChildSlot);
  }

// 2. Element
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) {
        // We don't insert a timeline event here, because otherwise it's
        // confusing that widgets that "don't update" (because they didn't
        // change) get "charged" on the timeline.
        if (child.slot != newSlot) {
          updateSlotForChild(child, newSlot);
        }
        newChild = child;
      } else if (hasSameSuperclass && Widget.canUpdate(child.widget, newWidget)) {
        
        // 更新Widget 
        // Element: 会: child.widget = newWidget;
        //  其他的Element(SingleChildRenderObjectWidget): 一般会先更新自己,然后再 updateChild
        // 仅仅更新了Widget, child (Element) 还是老的Element
        child.update(newWidget);
   
        newChild = child;
      } else {
        deactivateChild(child);
        newChild = inflateWidget(newWidget, newSlot);
      }
    } else {
      // child == nil的时候进入这里
      newChild = inflateWidget(newWidget, newSlot);
    }

    return newChild;
  }


// Element 类
// widget : MYAPP2 ,newSlot : _rootChildSlot
Element inflateWidget(Widget newWidget, Object? newSlot) {
  
  // MYAPP2 key 是 null
  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!;
    }
  }
  // 往下走 MYAPP2 调用createElement 返回对应的 element
  final Element newChild = newWidget.createElement();
  // 接下来就是 MYAPP2 element 去执行挂载
  // .... 这样就会一直去挂载,直到
  newChild.mount(this, newSlot);

  return newChild;
}
  

4. 我们接下来看看 markNeedsBuild

 // Element 类
  void markNeedsBuild() {
     _dirty = true;
     // owner来收集这些Element
     owner!.scheduleBuildFor(this);
  }

// BuildOwner
  void scheduleBuildFor(Element element) {
     
     // 收集这些Element
     _dirtyElements.add(element);
     element._inDirtyList = true;
  }