Flutter-widget生命周期
生命周期基本概念
什么是生命周期
- 本質(zhì)是回調(diào)方法(函數(shù))
- 讓開(kāi)發(fā)者知道這個(gè)widget它處于什么樣的狀態(tài)
有什么作用
1.監(jiān)聽(tīng)widget的事件
2.初始化數(shù)據(jù)
- 創(chuàng)建數(shù)據(jù)
- 發(fā)送網(wǎng)絡(luò)請(qǐng)求
3.內(nèi)存管理 - 銷(xiāo)毀數(shù)據(jù),銷(xiāo)毀監(jiān)聽(tīng)者
- 銷(xiāo)毀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)造方法來(lái)了!');
}
@override
void initState() {
print('State的init來(lái)了!');
super.initState();
}
@override
Widget build(BuildContext context) {
print('State的build來(lái)了!');
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ù)中移出的時(shí)候,就會(huì)調(diào)用!即將銷(xiā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)造方法來(lái)了!
flutter: State的init來(lái)了!
flutter: didChangeDependencies
flutter: State的build來(lái)了!
從上面的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í)行一次
- didChangeDependencies方法(改變依賴(lài)關(guān)系)
- 在StatefulWidget第一次創(chuàng)建的時(shí)候didChangeDependencies會(huì)被調(diào)用一次, 會(huì)在initState方法之后會(huì)被立即調(diào)用
- 從其他對(duì)象中依賴(lài)一些數(shù)據(jù)發(fā)生改變時(shí), 比如所依賴(lài)的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ù)中移出的時(shí)候,會(huì)先調(diào)用deactivate(),即將銷(xiāo)毀,然后調(diào)用dispose()
8當(dāng)Widget銷(xiāo)毀的時(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樹(shù)層級(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訪(fǎng)問(wèn)的共享數(shù)據(jù)!
static MyData of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<MyData>();
}
@override
bool updateShouldNotify(MyData oldWidget) {
//如果數(shù)據(jù)發(fā)生變化,其依賴(lài)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()方法,日常開(kāi)發(fā)中Theme.of(context).textTheme;、MediaQuery.of(context).size;都是使用這個(gè)技術(shù)。
Flutter渲染原理
在flutter渲染過(guò)程中,有三顆重要的樹(shù),Widget樹(shù),Element樹(shù),Render樹(shù)。下面是flutter中三種樹(shù)結(jié)構(gòu)

Widget樹(shù)
- 在整個(gè)Flutter項(xiàng)目結(jié)構(gòu)也是由很多個(gè)Widget構(gòu)成的, 本質(zhì)上就是一個(gè)Widget Tree
- 在上面的類(lèi)似Widget Tree結(jié)構(gòu)中, 很可能會(huì)有大量的Widget在樹(shù)結(jié)構(gòu)中存在引用關(guān)系, 而且每個(gè)Widget所依賴(lài)的配置和狀態(tài)發(fā)生改變的時(shí)候, Widget都會(huì)重新build, Widget會(huì)被不斷的銷(xiāo)毀和重建,那么意味著這棵樹(shù)非常不穩(wěn)定
- 所以Flutter Engin也不可能直接把Widget渲染到界面上, 這是極其損耗性能的, 所以在渲染層面Flutter引用了另外一個(gè)樹(shù)結(jié)構(gòu)RenderObject Tree
Render樹(shù)
- 每一個(gè)RenderObject都是渲染樹(shù)上的一個(gè)對(duì)象
- RenderObject層是渲染庫(kù)的核心, 最終Flutter Engin是把RenderObject真正渲染到界面上的,flutter引擎是針對(duì)Render樹(shù)進(jìn)行渲染,要注意并不是所有的Widget都會(huì)被獨(dú)立渲染,只有繼承RenderObjectWidget的才會(huì)創(chuàng)建RenderObject對(duì)象。
Element樹(shù)
- Element是Widget在樹(shù)中具有特定位置的是實(shí)例化
- Element Tree中的每一個(gè)Element是和Widget Tree中的每一個(gè)Widget一一對(duì)應(yīng)的
- 當(dāng)Widget Tree所依賴(lài)的狀態(tài)發(fā)生改變(更新或者重新創(chuàng)建Widget)的時(shí)候, Element根據(jù)拿到之前所保存的舊的Widget和新的Widget做一個(gè)對(duì)比, 判斷兩者的Key和類(lèi)型是否是相同的, 相同的就不需要重新創(chuàng)建, 有需要的話(huà), 只需要更新對(duì)應(yīng)的屬性,并將真正需要修改的部分同步到真實(shí)的RenderObject樹(shù)中,最大程度降低對(duì)真實(shí)渲染視圖的修改,提高渲染效率,而不是銷(xiāo)毀整個(gè)渲染視圖樹(shù)重建。
簡(jiǎn)而言之,Widget 樹(shù)就是配置信息的樹(shù),我們平時(shí)寫(xiě)代碼寫(xiě)的就是這棵樹(shù),RenderObject 樹(shù)是渲染樹(shù),負(fù)責(zé)計(jì)算布局,繪制,F(xiàn)lutter 引擎就是根據(jù)這棵樹(shù)來(lái)進(jìn)行渲染的,Element 樹(shù)作為中間者,管理著將 Widget 生成 RenderObject和一些更新操作。
對(duì)象的創(chuàng)建過(guò)程
Widget
來(lái)到Widget 類(lèi)里面可以看到有以下方法,所以每一個(gè)Widget都會(huì)創(chuàng)建一個(gè)Element對(duì)象,它會(huì)隱式調(diào)用createElement方法,將Element加入Element樹(shù)中。
@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方法,來(lái)創(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)建出來(lái)的elment會(huì)拿到傳過(guò)來(lái)的widget, 然后調(diào)用widget自己的build方法, 這也就是為什么所有的Widget創(chuàng)建出來(lái)之后都會(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有什么作用呢,我們下面就來(lái)看下
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來(lái)做一個(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引用也沒(méi)有發(fā)生改變,第一個(gè)Element指向之前的第二個(gè)widget,第二個(gè)Element指向之前的第三個(gè)widget,第三個(gè)Element被干掉

我們?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的分類(lèi)
Key本身是一個(gè)抽象類(lèi),子類(lèi)包含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 來(lái)保存它對(duì)應(yīng)的 Element。你可以通過(guò) 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)建出來(lái)后調(diào)用mount方法,在mount方法中會(huì)調(diào)用createRenderObject方法,來(lái)創(chuàng)建RenderObjectStatefulElement
StatefulWidget會(huì)創(chuàng)建StatefulElement,創(chuàng)建出來(lái)后調(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ù)時(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 來(lái)說(shuō) mount 主要執(zhí)行 widget 里的 build 方法,StatefulElement 執(zhí)行 build 方法的時(shí)候是執(zhí)行的 state 里面的 build 方法,并且將自身傳入,也就是常見(jiàn)的 BuildContext
3.BuildContext 是什么?
答:StatefulElement 執(zhí)行 build 方法的時(shí)候是執(zhí)行的 state 里面的 build 方法,并且將自身傳入,也就是 常見(jiàn)的 BuildContext。簡(jiǎn)而言之 BuidContext 就是 Element。
4.Widget 頻繁更改創(chuàng)建是否會(huì)影響性能?復(fù)用和更新機(jī)制是什么樣的?
答:不會(huì)影響性能,widget 只是簡(jiǎn)單的配置信息,并不直接涉及布局渲染相關(guān)。Element 層通過(guò)判斷新舊 widget 的runtimeType 和 key 是否相同決定是否可以直接更新之前的配置信息,也就是替換之前的 widget,而不必每次都重新創(chuàng)建新的 Element。
5.創(chuàng)建 Widget 里面的 Key 到底是什么作用?
答:Key 作為 Widget 的標(biāo)志,在widget 變更的時(shí)候通過(guò)判斷 Element 里面之前的 widget 的 runtimeType 和 key來(lái)決定是否能夠直接更新。