Flutter 生命周期和渲染原理

Flutter-widget生命周期

生命周期基本概念

什么是生命周期

  • 本質(zhì)是回調(diào)方法(函數(shù))
  • 讓開發(fā)者知道這個(gè)widget它處于什么樣的狀態(tài)

有什么作用

1.監(jiān)聽widget的事件
2.初始化數(shù)據(jù)

  • 創(chuàng)建數(shù)據(jù)
  • 發(fā)送網(wǎng)絡(luò)請(qǐng)求
    3.內(nèi)存管理
  • 銷毀數(shù)據(jù)唁毒,銷毀監(jiān)聽者
  • 銷毀timer等等

widget的生命周期

StatelessWidget

class MyHomePage extends StatelessWidget {
 final String title;
 MyHomePage({this.title}) {
   print('構(gòu)造函數(shù)被調(diào)用了!');
 }
 @override
 Widget build(BuildContext context) {
   print('build方法被調(diào)用了!');
   return Center(
     child: Text(title),
   );
 }
}

打印結(jié)果

flutter: 構(gòu)造函數(shù)被調(diào)用了!
flutter: build方法被調(diào)用了!

StatefulWidget

包含兩個(gè)對(duì)象Widget叫潦,State

class MyHomePage extends StatefulWidget {
  final String title;
  MyHomePage({this.title}) {
    print('構(gòu)造函數(shù)被調(diào)用了!');
  }
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _count = 0;

  _MyHomePageState() {
    print('State構(gòu)造方法來了!');
  }

  @override
  void initState() {
    print('State的init來了!');
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    print('State的build來了!');
    return Column(
      children: <Widget>[
        RaisedButton(
          child: Icon(Icons.add),
          onPressed: () {
            _count++;
            setState(() {});
          },
        ),
        Text('$_count'),
      ],
    );
  }

  @override
  void didChangeDependencies() {
    print('didChangeDependencies');
    super.didChangeDependencies();
  }

  //當(dāng)State對(duì)象從渲染樹中移出的時(shí)候,就會(huì)調(diào)用!即將銷毀!
  @override
  void deactivate() {
    super.deactivate();
  }

  @override
  void dispose() {
    print('State的dispose');
    super.dispose();
  }
}

打印結(jié)果

flutter: 構(gòu)造函數(shù)被調(diào)用了!
flutter: State構(gòu)造方法來了!
flutter: State的init來了!
flutter: didChangeDependencies
flutter: State的build來了!

從上面的demo可以看出StatefulWidget中函數(shù)調(diào)用順序?yàn)?/p>

1.Widget構(gòu)造方法
2.Widget的CreateState
3.State的構(gòu)造方法
4.State的initState方法

  • initState是StatefulWidget創(chuàng)建完后調(diào)用的第一個(gè)方法善玫,而且只執(zhí)行一次
  1. didChangeDependencies方法(改變依賴關(guān)系)
  • 在StatefulWidget第一次創(chuàng)建的時(shí)候didChangeDependencies會(huì)被調(diào)用一次, 會(huì)在initState方法之后會(huì)被立即調(diào)用
  • 從其他對(duì)象中依賴一些數(shù)據(jù)發(fā)生改變時(shí), 比如所依賴的InheritedWidget狀態(tài)發(fā)生改變時(shí), 也會(huì)被調(diào)用
    6.State的build方法
    當(dāng)調(diào)用setState方法,會(huì)重新調(diào)用build方法進(jìn)行渲染
    7.當(dāng)State對(duì)象從渲染樹中移出的時(shí)候,會(huì)先調(diào)用deactivate()割卖,即將銷毀,然后調(diào)用dispose()
    8當(dāng)Widget銷毀的時(shí)候患雏,調(diào)用State的dispose

didChangeDependencies()

這里我們看一個(gè)demo

class InheritedDemo extends StatefulWidget {
  @override
  _InheritedDemoState createState() => _InheritedDemoState();
}

class _InheritedDemoState extends State<InheritedDemo> {
  int count = 1;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        Test1(count),
        RaisedButton(
          child: Text('我是按鈕'),
          //setState!

          onPressed: () => setState(() {
            count++;
          }),
        )
      ],
    );
  }
}

class Test1 extends StatelessWidget {
 final count;
 Test1(this.count);
  @override
  Widget build(BuildContext context) {
    return Test2(count);
  }
}

class Test2 extends StatelessWidget {
 final count;
 Test2(this.count);
  @override
  Widget build(BuildContext context) {
    return Test3(count);
  }
}

class Test3 extends StatefulWidget {
 final count;
 Test3(this.count);
  @override
  _Test3State createState() => _Test3State();
}

class _Test3State extends State<Test3> {
  @override
  Widget build(BuildContext context) {
    return Text(widget.count.toString());
  }

  @override
  void didChangeDependencies() {
    print('didChangeDependencies');
    super.didChangeDependencies();
  }
}


這里widget樹層級(jí)非常多鹏溯,一層一層的傳遞count,會(huì)很繁瑣淹仑,這里我們可以使用數(shù)據(jù)共享的方式(也可以成為狀態(tài)管理)丙挽,使用InheritedWidget,能做到其子Widget能共享InheritedWidget的數(shù)據(jù)

import 'package:flutter/material.dart';

//數(shù)據(jù)共享!
class MyData extends InheritedWidget {
  MyData({this.data, Widget child}) : super(child: child);
  final int data; //需要在子Widget中共享的數(shù)據(jù)!

  //提供一個(gè)方法讓子Widget訪問的共享數(shù)據(jù)!
  static MyData of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<MyData>();
  }

  @override
  bool updateShouldNotify(MyData oldWidget) {
//如果數(shù)據(jù)發(fā)生變化匀借,其依賴InheritedWidget的子Widget就能收到通知颜阐,子Widget就會(huì)調(diào)用build()
    return oldWidget.data != data;
  }
}

class InheritedDemo extends StatefulWidget {
  @override
  _InheritedDemoState createState() => _InheritedDemoState();
}

class _InheritedDemoState extends State<InheritedDemo> {
  int count = 1;

  @override
  Widget build(BuildContext context) {
////Column被包在了MyData中,MyData其子Widget 都能使用 data字段
    return MyData(
      data: count,
      child: Column(
        children: <Widget>[
          Test1(),
          RaisedButton(
            child: Text('我是按鈕'),
            //setState!

            onPressed: () => setState(() {
              count++;
            }),
          )
        ],
      ),
    );
  }
}

class Test1 extends StatelessWidget {
//  final count;
//  Test1(this.count);
  @override
  Widget build(BuildContext context) {
    return Test2();
  }
}

class Test2 extends StatelessWidget {
//  final count;
//  Test2(this.count);
  @override
  Widget build(BuildContext context) {
    return Test3();
  }
}

class Test3 extends StatefulWidget {
//  final count;
//  Test3(this.count);
  @override
  _Test3State createState() => _Test3State();
}

class _Test3State extends State<Test3> {
  @override
  Widget build(BuildContext context) {
    return Text(MyData.of(context).data.toString());
  }

  @override
  void didChangeDependencies() {
    print('didChangeDependencies');
    super.didChangeDependencies();
  }
}


這時(shí)候我們?cè)冱c(diǎn)擊按鈕改變count值時(shí)怀吻,發(fā)現(xiàn)每次都會(huì)調(diào)用didChangeDependencies()方法瞬浓,日常開發(fā)中Theme.of(context).textTheme;、MediaQuery.of(context).size;都是使用這個(gè)技術(shù)蓬坡。

Flutter渲染原理

在flutter渲染過程中猿棉,有三顆重要的樹磅叛,Widget樹,Element樹萨赁,Render樹弊琴。下面是flutter中三種樹結(jié)構(gòu)


截屏2021-08-18 下午2.59.03.png

Widget樹

  • 在整個(gè)Flutter項(xiàng)目結(jié)構(gòu)也是由很多個(gè)Widget構(gòu)成的, 本質(zhì)上就是一個(gè)Widget Tree
  • 在上面的類似Widget Tree結(jié)構(gòu)中, 很可能會(huì)有大量的Widget在樹結(jié)構(gòu)中存在引用關(guān)系, 而且每個(gè)Widget所依賴的配置和狀態(tài)發(fā)生改變的時(shí)候, Widget都會(huì)重新build, Widget會(huì)被不斷的銷毀和重建,那么意味著這棵樹非常不穩(wěn)定
  • 所以Flutter Engin也不可能直接把Widget渲染到界面上, 這是極其損耗性能的, 所以在渲染層面Flutter引用了另外一個(gè)樹結(jié)構(gòu)RenderObject Tree

Render樹

  • 每一個(gè)RenderObject都是渲染樹上的一個(gè)對(duì)象
  • RenderObject層是渲染庫(kù)的核心, 最終Flutter Engin是把RenderObject真正渲染到界面上的杖爽,flutter引擎是針對(duì)Render樹進(jìn)行渲染敲董,要注意并不是所有的Widget都會(huì)被獨(dú)立渲染,只有繼承RenderObjectWidget的才會(huì)創(chuàng)建RenderObject對(duì)象慰安。

Element樹

  • Element是Widget在樹中具有特定位置的是實(shí)例化
  • Element Tree中的每一個(gè)Element是和Widget Tree中的每一個(gè)Widget一一對(duì)應(yīng)的
  • 當(dāng)Widget Tree所依賴的狀態(tài)發(fā)生改變(更新或者重新創(chuàng)建Widget)的時(shí)候, Element根據(jù)拿到之前所保存的舊的Widget和新的Widget做一個(gè)對(duì)比, 判斷兩者的Key和類型是否是相同的, 相同的就不需要重新創(chuàng)建, 有需要的話, 只需要更新對(duì)應(yīng)的屬性腋寨,并將真正需要修改的部分同步到真實(shí)的RenderObject樹中,最大程度降低對(duì)真實(shí)渲染視圖的修改化焕,提高渲染效率萄窜,而不是銷毀整個(gè)渲染視圖樹重建。

簡(jiǎn)而言之撒桨,Widget 樹就是配置信息的樹查刻,我們平時(shí)寫代碼寫的就是這棵樹,RenderObject 樹是渲染樹凤类,負(fù)責(zé)計(jì)算布局穗泵,繪制,F(xiàn)lutter 引擎就是根據(jù)這棵樹來進(jìn)行渲染的谜疤,Element 樹作為中間者佃延,管理著將 Widget 生成 RenderObject和一些更新操作。

對(duì)象的創(chuàng)建過程

Widget

來到Widget 類里面可以看到有以下方法茎截,所以每一個(gè)Widget都會(huì)創(chuàng)建一個(gè)Element對(duì)象苇侵,它會(huì)隱式調(diào)用createElement方法,將Element加入Element樹中企锌。

   @protected
  @factory
  Element createElement();

我們?cè)倏匆幌翪olumn榆浓,可以看到它繼承自Flex,F(xiàn)lex繼承自MultiChildRenderObjectWidget撕攒,MultiChildRenderObjectWidget繼承自RenderObjectWidget陡鹃,點(diǎn)進(jìn)去可以看到里面有一個(gè)方法createRenderObject和創(chuàng)建RenderObjectElement的方法

abstract class RenderObjectWidget extends Widget {
  /// Abstract const constructor. This constructor enables subclasses to provide
  /// const constructors so that they can be used in const expressions.
  const RenderObjectWidget({ Key? key }) : super(key: key);

  /// RenderObjectWidgets always inflate to a [RenderObjectElement] subclass.
  @override
  @factory
  RenderObjectElement createElement();

  /// Creates an instance of the [RenderObject] class that this
  /// [RenderObjectWidget] represents, using the configuration described by this
  /// [RenderObjectWidget].
  ///
  /// This method should not do anything with the children of the render object.
  /// That should instead be handled by the method that overrides
  /// [RenderObjectElement.mount] in the object rendered by this object's
  /// [createElement] method. See, for example,
  /// [SingleChildRenderObjectElement.mount].
  @protected
  @factory
  RenderObject createRenderObject(BuildContext context);

在mount方法中會(huì)調(diào)用createRenderObject方法,來創(chuàng)建RenderObject

@override
  void mount(Element? parent, dynamic newSlot) {
    super.mount(parent, newSlot);
    assert(() {
      _debugDoingBuild = true;
      return true;
    }());
    _renderObject = widget.createRenderObject(this);
    assert(() {
      _debugDoingBuild = false;
      return true;
    }());
    assert(() {
      _debugUpdateRenderObjectOwner();
      return true;
    }());
    assert(_slot == newSlot);
    attachRenderObject(newSlot);
    _dirty = false;
  }

我們?cè)倏匆幌鲁S玫腟tatefulWidget和StatelessWidget

  • StatelessWidget
    這里會(huì)創(chuàng)建一個(gè)StatelessElement抖坪,繼承自ComponentElement
abstract class StatelessWidget extends Widget {
  /// Initializes [key] for subclasses.
  const StatelessWidget({ Key? key }) : super(key: key);

  /// Creates a [StatelessElement] to manage this widget's location in the tree.
  ///
  /// It is uncommon for subclasses to override this method.
  @override
  StatelessElement createElement() => StatelessElement(this);

這里可以看到在創(chuàng)建Element之后, 創(chuàng)建出來的elment會(huì)拿到傳過來的widget, 然后調(diào)用widget自己的build方法, 這也就是為什么所有的Widget創(chuàng)建出來之后都會(huì)調(diào)用build方法的原因

class StatelessElement extends ComponentElement {
  /// Creates an element that uses the given widget as its configuration.
  StatelessElement(StatelessWidget widget) : super(widget);

  @override
  StatelessWidget get widget => super.widget as StatelessWidget;

  @override
  Widget build() => widget.build(this);

  @override
  void update(StatelessWidget newWidget) {
    super.update(newWidget);
    assert(widget == newWidget);
    _dirty = true;
    rebuild();
  }
}
  • StatefulWidget
    這里會(huì)創(chuàng)建一個(gè)StatefulElement萍鲸,它繼承自ComponentElement
abstract class StatefulWidget extends Widget {
  /// Initializes [key] for subclasses.
  const StatefulWidget({ Key? key }) : super(key: key);

  /// Creates a [StatefulElement] to manage this widget's location in the tree.
  ///
  /// It is uncommon for subclasses to override this method.
  @override
  StatefulElement createElement() => StatefulElement(this);

  /// Creates the mutable state for this widget at a given location in the tree.
  ///
  /// Subclasses should override this method to return a newly created
  /// instance of their associated [State] subclass:
  ///
  /// ```dart
  /// @override
  /// _MyState createState() => _MyState();
  /// ```
  ///
  /// The framework can call this method multiple times over the lifetime of
  /// a [StatefulWidget]. For example, if the widget is inserted into the tree
  /// in multiple locations, the framework will create a separate [State] object
  /// for each location. Similarly, if the widget is removed from the tree and
  /// later inserted into the tree again, the framework will call [createState]
  /// again to create a fresh [State] object, simplifying the lifecycle of
  /// [State] objects.
  @protected
  @factory
  State createState(); // ignore: no_logic_in_create_state, this is the original sin
}

StatefulElement會(huì)調(diào)用widget的createState(),這里調(diào)用build的時(shí)候擦俐,調(diào)用的是state中的build方法:

/// An [Element] that uses a [StatefulWidget] as its configuration.
class StatefulElement extends ComponentElement {
  /// Creates an element that uses the given widget as its configuration.
  StatefulElement(StatefulWidget widget)
      : state = widget.createState(),
        super(widget) {
    assert(() {
      if (!state._debugTypesAreRight(widget)) {
        throw FlutterError.fromParts(<DiagnosticsNode>[
          ErrorSummary('StatefulWidget.createState must return a subtype of State<${widget.runtimeType}>'),
          ErrorDescription(
            'The createState function for ${widget.runtimeType} returned a state '
            'of type ${state.runtimeType}, which is not a subtype of '
            'State<${widget.runtimeType}>, violating the contract for createState.'
          ),
        ]);
      }
      return true;
    }());
    assert(state._element == null);
    state._element = this;
    assert(
      state._widget == null,
      'The createState function for $widget returned an old or invalid state '
      'instance: ${state._widget}, which is not null, violating the contract '
      'for createState.',
    );
    state._widget = widget;
    assert(state._debugLifecycleState == _StateLifecycle.created);
  }

  @override
  Widget build() => state.build(this);
  • BuildContext
    從上面的代碼可以看到build方法傳入的參數(shù)都是Element脊阴,所以本質(zhì)上BuildContext就是當(dāng)前的Element

Key的原理

我們之前創(chuàng)建的每一個(gè)Widget, 在其構(gòu)造方法中我們都會(huì)看到一個(gè)參數(shù)Key,那個(gè)這個(gè)key有什么作用呢,我們下面就來看下

abstract class StatefulWidget extends Widget {
  /// Initializes [key] for subclasses.
  const StatefulWidget({ Key? key }) : super(key: key);

先看一個(gè)demo嘿期,希望每次點(diǎn)擊按鈕后刪除數(shù)組第一個(gè)元素品擎,先看第一種實(shí)現(xiàn)方式,用StatelessWidget备徐,可以看到運(yùn)行效果正常萄传,依次刪除

class KeyDemo extends StatefulWidget {
  @override
  _KeyDemoState createState() => _KeyDemoState();
}

class _KeyDemoState extends State<KeyDemo> {
  List<Widget> items = [
    StlItem(
      'aaaaa',

    ),
    StlItem(
      'bbbbb',

    ),
    StlItem(
      'ccccc',

    ),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('keyDemo'),
      ),
      body: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: items,
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () {
          setState(() {
            items.removeAt(0);
          });
        },
      ),
    );
  }
}


//做一個(gè)正方形!
class StlItem extends StatelessWidget {
  final title;
  StlItem(this.title);
  final _color = Color.fromRGBO(
      Random().nextInt(256), Random().nextInt(256), Random().nextInt(256), 1.0);
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 100,
      height: 100,
      color: _color,
      child: Text(title),
    );
  }
}

現(xiàn)在我們用StatefulWidget來做一個(gè)正方形,點(diǎn)擊按鈕刪除時(shí)蜜猾,發(fā)生了一個(gè)神奇的事秀菱,刪除的第一條數(shù)據(jù),但是從顏色上看蹭睡,是刪除了最后一條衍菱,好像復(fù)用了

class StfulItem extends StatefulWidget {
  final title;
  StfulItem(this.title, {Key key}) : super(key: key);

  @override
  _StfulItemState createState() => _StfulItemState();
}

class _StfulItemState extends State<StfulItem> {
  final _color = Color.fromRGBO(
      Random().nextInt(256), Random().nextInt(256), Random().nextInt(256), 1.0);
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 100,
      height: 100,
      color: _color,
      child: Text(widget.title),
    );
  }
}

查看Widget源碼,里面有段代碼棠笑,是否要更新Element是由這個(gè)方法決定的梦碗,做到增量更新

  static bool canUpdate(Widget oldWidget, Widget newWidget) {
    return oldWidget.runtimeType == newWidget.runtimeType
        && oldWidget.key == newWidget.key;
  }

當(dāng)不設(shè)置key的是時(shí)候,右邊的element會(huì)從前面第一個(gè)依次判斷比較蓖救,第一個(gè)Element跟之前第二個(gè)widget比較,canUpdate返回true印屁,所以Element中對(duì)應(yīng)的State引用也沒有發(fā)生改變循捺,第一個(gè)Element指向之前的第二個(gè)widget,第二個(gè)Element指向之前的第三個(gè)widget雄人,第三個(gè)Element被干掉

截屏2021-08-23 下午5.41.49.png

我們?cè)谥暗幕A(chǔ)上从橘,為每一個(gè)StfulItem添加一個(gè)key

 List<Widget> items = [
    StfulItem(
      'aaaaa',
      key: ValueKey(111),

    ),
    StfulItem(
      'bbbbb',
      key: ValueKey(222),
    ),
    StfulItem(
      'ccccc',
      key: ValueKey(333),
    ),
  ];

運(yùn)行代碼,效果正常础钠,根據(jù)runtimeType和key進(jìn)行比對(duì), 和新的Widget Tree相同的會(huì)被繼續(xù)復(fù)用, 否則就會(huì)刪除

Key的分類

Key本身是一個(gè)抽象類恰力,子類包含LocalKey和GlobalKey。

  • LocalKey
    1.ValueKey旗吁,以一個(gè)數(shù)據(jù)作為Key踩萎,如:數(shù)字,字符
    class ValueKey<T> extends LocalKey {
    /// Creates a key that delegates its [operator==] to the given value.
    const ValueKey(this.value);
    
    /// The value to which this key delegates its [operator==]
    final T value;
    
    @override
    bool operator ==(Object other) {
    if (other.runtimeType != runtimeType)
      return false;
    return other is ValueKey<T>
        && other.value == value;
    }
    
    

2.ObjectKey很钓,以object對(duì)象作為Key香府,例如 ObjectKey(Text('222')),

class ObjectKey extends LocalKey {
/// Creates a key that uses [identical] on [value] for its [operator==].
const ObjectKey(this.value);

/// The object whose identity is used by this key's [operator==].
final Object? value;

@override
bool operator ==(Object other) {
  if (other.runtimeType != runtimeType)
    return false;
  return other is ObjectKey
      && identical(other.value, value);
}

3.UniqueKey 可以保證key的唯一性(一旦使用UniqueKey那么就不存在Element復(fù)用了)

class UniqueKey extends LocalKey {
/// Creates a key that is equal only to itself.
///
/// The key cannot be created with a const constructor because that implies
/// that all instantiated keys would be the same instance and therefore not
/// be unique.
// ignore: prefer_const_constructors_in_immutables , never use const for this class
UniqueKey();

@override
String toString() => '[#${shortHash(this)}]';
}
  • GlobalKey
    GlobalKey 可以獲取到對(duì)應(yīng)的widget的state對(duì)象
    GlobalKey 使用了一個(gè)靜態(tài)常量 Map 來保存它對(duì)應(yīng)的 Element。你可以通過 GlobalKey 找到持有該GlobalKey的 Widget码倦,State 和 Element企孩。
    需要注意:GlobalKey 是非常昂貴的,需要謹(jǐn)慎使用袁稽。
abstract class GlobalKey<T extends State<StatefulWidget>> extends Key {
 /// Creates a [LabeledGlobalKey], which is a [GlobalKey] with a label used for
 /// debugging.
 ///
 /// The label is purely for debugging and not used for comparing the identity
 /// of the key.
 factory GlobalKey({ String? debugLabel }) => LabeledGlobalKey<T>(debugLabel);

 /// Creates a global key without a label.
 ///
 /// Used by subclasses because the factory constructor shadows the implicit
 /// constructor.
 const GlobalKey.constructor() : super.empty();

 static final Map<GlobalKey, Element> _registry = <GlobalKey, Element>{};
 static final Set<Element> _debugIllFatedElements = HashSet<Element>();
 // This map keeps track which child reserves the global key with the parent.
 // Parent, child -> global key.
 // This provides us a way to remove old reservation while parent rebuilds the
 // child in the same slot.
 static final Map<Element, Map<Element, GlobalKey>> _debugReservations = <Element, Map<Element, GlobalKey>>{};


這里我們看一個(gè)使用GlobalKey的demo勿璃,一個(gè)StatelessWidget包含子StatefulWidget,點(diǎn)擊父親里面的一個(gè)按鈕改變子節(jié)點(diǎn)的內(nèi)容

class GlobalKeyDemo extends StatelessWidget {
final GlobalKey<_ChildPageState> _globalKey = GlobalKey();

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text('GlobalKeyDemo'),
    ),
    body: ChildPage(
      key: _globalKey,
    ),
    floatingActionButton: FloatingActionButton(
      child: Icon(Icons.add),
      onPressed: () {
        _globalKey.currentState.data =
            'old:' + _globalKey.currentState.count.toString();
        _globalKey.currentState.count++;

        _globalKey.currentState.setState(() {});
      },
    ),
  );
}
}

class ChildPage extends StatefulWidget {
ChildPage({Key key}) : super(key: key);
@override
_ChildPageState createState() => _ChildPageState();
}

class _ChildPageState extends State<ChildPage> {
int count = 0;
String data = 'hello';
@override
Widget build(BuildContext context) {
  return Center(
    child: Column(
      children: <Widget>[
        Text(count.toString()),
        Text(data),
      ],
    ),
  );
}
}

總結(jié)

1.Widget會(huì)隱式調(diào)用createElement方法創(chuàng)建Element,每一個(gè)Widget都會(huì)創(chuàng)建一個(gè)Element對(duì)象补疑,然后調(diào)用mount方法闻葵,但是不同Element中mount的處理方式不同
2.會(huì)創(chuàng)建三種Element

  • RenderElement
    RenderElement主要是創(chuàng)建RenderObject對(duì)象,只有繼承自RenderObjectWidget的Widget會(huì)創(chuàng)建RenderObjectElement癣丧,創(chuàng)建步驟先創(chuàng)建RanderElement槽畔,創(chuàng)建出來后調(diào)用mount方法,在mount方法中會(huì)調(diào)用createRenderObject方法胁编,來創(chuàng)建RenderObject

  • StatefulElement
    StatefulWidget會(huì)創(chuàng)建StatefulElement厢钧,創(chuàng)建出來后調(diào)用createState方法,創(chuàng)建state嬉橙,將Widget賦值給state早直,最后調(diào)用state的build方法,并且將Element傳出去

  • StatelessElement

StatelessWidget會(huì)創(chuàng)建StatelessElement市框,這里主要就是調(diào)用build方法霞扬,將Element傳出去

補(bǔ)充幾個(gè)面試題

1.createState 方法在什么時(shí)候調(diào)用?state 里面為啥可以直接獲取到 widget 對(duì)象枫振?

答:Flutter 會(huì)在遍歷 Widget 樹時(shí)調(diào)用 Widget 里面的 createElement 方法去生成對(duì)應(yīng)節(jié)點(diǎn)的 Element 對(duì)象喻圃,同時(shí)執(zhí)行 StatefulWidget 里面的 createState 方法創(chuàng)建 state,并且賦值給 Element 里的 _state 屬性粪滤,當(dāng)前 widget 也同時(shí)賦值給了 state 里的_widget斧拍,state 里面有個(gè) widget 的get 方法可以獲取到 _widget 對(duì)象。

2.build 方法是在什么時(shí)候調(diào)用的杖小?

答:Element 創(chuàng)建好以后 Flutter 框架會(huì)執(zhí)行 mount 方法肆汹,對(duì)于非渲染的 ComponentElement 來說 mount 主要執(zhí)行 widget 里的 build 方法,StatefulElement 執(zhí)行 build 方法的時(shí)候是執(zhí)行的 state 里面的 build 方法予权,并且將自身傳入昂勉,也就是常見的 BuildContext

3.BuildContext 是什么?

答:StatefulElement 執(zhí)行 build 方法的時(shí)候是執(zhí)行的 state 里面的 build 方法扫腺,并且將自身傳入岗照,也就是 常見的 BuildContext。簡(jiǎn)而言之 BuidContext 就是 Element斧账。

4.Widget 頻繁更改創(chuàng)建是否會(huì)影響性能谴返?復(fù)用和更新機(jī)制是什么樣的?

答:不會(huì)影響性能咧织,widget 只是簡(jiǎn)單的配置信息嗓袱,并不直接涉及布局渲染相關(guān)。Element 層通過判斷新舊 widget 的runtimeType 和 key 是否相同決定是否可以直接更新之前的配置信息习绢,也就是替換之前的 widget渠抹,而不必每次都重新創(chuàng)建新的 Element蝙昙。

5.創(chuàng)建 Widget 里面的 Key 到底是什么作用?
答:Key 作為 Widget 的標(biāo)志梧却,在widget 變更的時(shí)候通過判斷 Element 里面之前的 widget 的 runtimeType 和 key來決定是否能夠直接更新奇颠。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市放航,隨后出現(xiàn)的幾起案子烈拒,更是在濱河造成了極大的恐慌,老刑警劉巖广鳍,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件荆几,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡赊时,警方通過查閱死者的電腦和手機(jī)吨铸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來祖秒,“玉大人诞吱,你說我怎么就攤上這事〗叻欤” “怎么了房维?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)歌馍。 經(jīng)常有香客問我握巢,道長(zhǎng),這世上最難降的妖魔是什么松却? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮溅话,結(jié)果婚禮上晓锻,老公的妹妹穿的比我還像新娘。我一直安慰自己飞几,他們只是感情好砚哆,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著屑墨,像睡著了一般躁锁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上卵史,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天战转,我揣著相機(jī)與錄音,去河邊找鬼以躯。 笑死槐秧,一個(gè)胖子當(dāng)著我的面吹牛啄踊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播刁标,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼颠通,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了膀懈?” 一聲冷哼從身側(cè)響起顿锰,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎启搂,沒想到半個(gè)月后硼控,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡狐血,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年淀歇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片匈织。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡浪默,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出缀匕,到底是詐尸還是另有隱情纳决,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布乡小,位于F島的核電站阔加,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏满钟。R本人自食惡果不足惜胜榔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望湃番。 院中可真熱鬧夭织,春花似錦、人聲如沸吠撮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)泥兰。三九已至弄屡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鞋诗,已是汗流浹背膀捷。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留师脂,地道東北人担孔。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓江锨,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親糕篇。 傳聞我的和親對(duì)象是個(gè)殘疾皇子啄育,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 生命周期的基本概念:生命周期的本質(zhì)上就是回調(diào)方法旺聚,這個(gè)回調(diào)方法能夠讓我們知道這個(gè)widget處于一個(gè)什么樣的狀態(tài)正林。...
    HardCabbage閱讀 917評(píng)論 0 3
  • 生命周期概念 1.生命周期本質(zhì)是回調(diào)方法和函數(shù)2.通俗的講就是你的封裝的Widget(小組件)處于什么狀態(tài) 生命周...
    憶往不糾閱讀 346評(píng)論 0 1
  • 1.生命周期 生命周期是別人封裝好的一套方法接口,然后提供回調(diào)方法給我們調(diào)用,生命周期本質(zhì)是回調(diào)方法; 2.生命周...
    ChaosHeart閱讀 1,340評(píng)論 0 1
  • 一客叉、生命周期的基本概念 1敦间、什么是生命周期 說白了就是回調(diào)方法(函數(shù)) 讓你知道我封裝好的這個(gè)Widget它處于什...
    致青春_bf42閱讀 404評(píng)論 0 0
  • 程序的入口 類似iOS開發(fā)中的main方法一樣 flutter工程也是通過main方法啟動(dòng): 這里的runApp方...
    番茄炒西紅柿啊閱讀 578評(píng)論 0 0