Flutter - Widget生命周期與渲染原理

生命周期的基本概念:
生命周期的本質(zhì)上就是回調(diào)方法,這個(gè)回調(diào)方法能夠讓我們知道這個(gè)widget處于一個(gè)什么樣的狀態(tài)。我們可以實(shí)現(xiàn)這個(gè)方法去監(jiān)聽widget的生命周期。
生命周期的作用:

  • 監(jiān)聽widget事件
  • 初始化數(shù)據(jù),創(chuàng)建數(shù)據(jù),發(fā)送網(wǎng)絡(luò)請求等等
  • 內(nèi)存管理,數(shù)據(jù)銷毀,監(jiān)聽銷毀等等
    Widget的生命周期

StatelessWidget

無狀態(tài)的widget比較簡單,StatelessWidget只有一個(gè)build方法和構(gòu)造方法
StatelessWidget會(huì)在底層調(diào)用
StatelessElement createElement() => StatelessElement(this);這個(gè)方法來創(chuàng)建一個(gè)Element樹,在StatelessElement中調(diào)用
Widget build() => widget.build(this);來構(gòu)建widget。

  • 構(gòu)造方法
  • build方法
    代碼驗(yàn)證一下
class LessApp extends StatelessWidget {
  final String title;
  LessApp({this.title}){
    print('構(gòu)造函數(shù)被調(diào)用了');
  }
  @override
  Widget build(BuildContext context) {
     print('build被調(diào)用了');
    return Center(
      child: Text('hello flutter'),
    );
  }
}

上面運(yùn)行的結(jié)果
運(yùn)行結(jié)果

StatefulWidget

StatefulWidget包含兩個(gè)對象Widget和State,下面介紹一下它的生命周期

  • Widget構(gòu)造方法
  • Widget的createState
  • State的構(gòu)造方法
  • State的initState方法
    源碼解釋:Called when this object is inserted into the tree.當(dāng)這個(gè)對象被添加到Widget樹中會(huì)被調(diào)用
  • didChangeDependencies方法(依賴關(guān)系改變)
    源碼解釋:Called when a dependency of this [State] object changes.當(dāng)該[State]對象的依賴項(xiàng)發(fā)生更改時(shí)調(diào)用。
  • State的build方法
    我們可以看下源碼,在StatefulWidget源碼里面會(huì)創(chuàng)建一個(gè) Element
    StatefulElement createElement() => StatefulElement(this);
    StatefulElement里面會(huì)創(chuàng)建一個(gè)狀態(tài)_state,然后會(huì)重寫build方法
    Widget build() => _state.build(this);這個(gè)this就是MaterialApp,MaterialApp的Scaffold的body是下面的代碼中的StateApp,這樣就掉用到了該State下的build方法,同時(shí)將widget保存在_state中_state._widget = widget;這也是為什么在state中能夠使用widget來訪問變量,其他的地方則不行的原因。
  • didUpdateWidget
    這個(gè)一般用在狀態(tài)改變,并且沿著widget傳值使用,比如調(diào)用了setState.
    實(shí)際上這里flutter框架會(huì)創(chuàng)建一個(gè)新的Widget,綁定本State,并在這個(gè)函數(shù)中傳遞老的Widget。
    這個(gè)函數(shù)一般用于比較新、老Widget,看看哪些屬性改變了
  • deactivate
    Called when this object is removed from the tree.當(dāng)這個(gè)對象從渲染樹中移除的時(shí)候會(huì)調(diào)用這個(gè)方法。(即將銷毀)
  • dispose
    Called when this object is removed from the tree permanently,當(dāng)對象從渲染樹上已經(jīng)移除調(diào)用該方法。
    下面使用示例來詳細(xì)說明,我們設(shè)置了一個(gè)按鈕和一個(gè)text,點(diǎn)擊按鈕text文字會(huì)增量變化。
class StateApp extends StatefulWidget {
  final String title;
  StateApp({this.title}){
    print('構(gòu)造函數(shù)被調(diào)用了');
  }
  @override
  _MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<StateApp> {
  _MyAppState(){

    print('State的構(gòu)造方法來了');
  }
 int _count =0;

  @override
  void initState() {
    print('State的init來了');
    // TODO: implement initState
    super.initState();

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

             });
            }
        ),
        Text('$_count'),
      ],
    );
  }
  @override
  void dispose() {
    // TODO: implement dispose
    print('dispose來了');
    super.dispose();
  }
  @override
  void didChangeDependencies() {
    // TODO: implement didChangeDependencies
    super.didChangeDependencies();
  }
 @override
  void deactivate() {
    // TODO: implement deactivate
    super.deactivate();
  }
  
  
}

上面這段代碼的運(yùn)行結(jié)果

截屏2020-06-16 14.30.21.png

然后我們點(diǎn)擊按鈕,每次點(diǎn)擊都會(huì)重新調(diào)用build方法改變界面。為什么呢,因?yàn)楫?dāng)我們調(diào)用setState的時(shí)候,追蹤源碼發(fā)現(xiàn)它調(diào)用的是 _element.markNeedsBuild()->rebuild()-> _dirtyElements.add(element)重新加到Element樹中進(jìn)行渲染。

Widget渲染原理

首先flutter中有三棵樹,Widget樹、Element樹、Render樹

  • Widget Tree :隱式調(diào)用createElement方法
    flutter引擎并不是直接渲染W(wǎng)idget樹,因?yàn)閣idget每一次build都會(huì)重新創(chuàng)建,widget非常不穩(wěn)定,如果直接渲染性能消耗嚴(yán)重,所以widget不是引擎直接渲染的樹。
    每一個(gè)Widget都會(huì)創(chuàng)建一個(gè)Element對象,隱式調(diào)用createElement方法,Element加入Element樹中。
  • Element Tree有三中RenderElement、StatefulElement、StatelessElement。

RenderElement
主要是創(chuàng)建RenderObject對象
1.創(chuàng)建RanderElement,只要加入Element樹里面就會(huì)執(zhí)行mount方法(createElement執(zhí)行完就會(huì)調(diào)用)
2.Flutter會(huì)調(diào)用mount方法,調(diào)用createRanderObject方法

StatefulElement
StatefulElement繼承ComponentElement
1.調(diào)用createState方法,創(chuàng)建State
2.將Widget賦值給state
3.調(diào)用state的build方法 并且將自己(Element)傳出去,build里面的context 就是Widget的Element。

StatelessElement
StatelessElement繼承ComponentElement
1.StatelessWidget會(huì)創(chuàng)建StatelessElement
2.主要就是調(diào)用build方法 并且將自己(Element)傳出去。

  • Render Tree:RenderElement主要是創(chuàng)建RenderObject對象
    我們的渲染引擎直接渲染的是Render樹,Render樹放的是RenderObject對象,追蹤源碼可以得知并不是所有的widget都會(huì)加入到Render中,比如我們的StatelessWidget、和StatefulWidget就不是繼承RenderObjectWidget??偨Y(jié):并不是所有的widget都會(huì)被獨(dú)立渲染,只有繼承RenderObjectWidget的才會(huì)創(chuàng)建RenderObject對象,才會(huì)被加入到Render Tree。

總結(jié):上文中我們已經(jīng)知道flutter直接渲染的是Render樹,而widget樹非常不穩(wěn)定,那么就需要一個(gè)橋梁來對比老的widget和新的widget有什么樣的變化,這個(gè)橋梁就是Element樹,創(chuàng)建widget與之對應(yīng)就會(huì)創(chuàng)建一個(gè)一模一樣的Element樹。Element既引用widget樹同時(shí)也通知Render樹哪些是變化的,哪些是沒有變化的,再由渲染引擎來渲染,這樣就大大的提高了效率。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容