Flutter入門(十一)生命周期&渲染原理

前言

在做移動端開發(fā)時习柠,不論是安卓的Activity還是iOS的UIViewController都有自己的生命周期喳坠,同理Flutter也有自己的生命周期构回,今天我們就通過以下幾個方面來探索一下:

  • 1.生命周期的基本概念
  • 2.Widget的生命周期
  • 3.Flutter渲染原理

1.生命周期的基本概念

Flutter生命周期流程

1.1什么是生命周期

  • 1.說白了就是回調(diào)函數(shù)
  • 2.讓你知道封裝好的這個Widget處于什么樣的狀態(tài)

1.2生命周期的作用

  • 1.初始化數(shù)據(jù)
    1.1創(chuàng)建變量谷炸、常量
    1.2發(fā)送網(wǎng)絡(luò)請求

  • 2.監(jiān)聽小部件的事件

  • 3.管理內(nèi)存
    3.1銷毀數(shù)據(jù)、銷毀監(jiān)聽者
    3.2銷毀Timer等等

2.Widget的生命周期

2.1StatelessWidget的生命周期

class MyWidget extends StatelessWidget {
  const MyWidget({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}
  • 1.構(gòu)造方法
  • 2.build方法

對于StatelessWidget來說畦徘,生命周期只有構(gòu)造和build過程毕籽。build是用來創(chuàng)建Widget的,在每次頁面刷新時會調(diào)用build

2.2StatefulWidget的生命周期

class MyHomePage extends StatefulWidget {
  final String title;

  MyHomePage({Key? key, required this.title}) : super(key: key) {
    print('Widget構(gòu)造方法來了');
  }

  @override
  State<MyHomePage> createState() {
    print('Widget的createState方法調(diào)用了');
    return _MyHomePageState();
  }
}

class _MyHomePageState extends State<MyHomePage> {
  _MyHomePageState() {
    print('State構(gòu)造方法來了');
  }

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

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

  int _count = 0;

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

  @override
  void dispose() {
    print('State的dispose來了');
    super.dispose();
  }
}
  • 1.Widget構(gòu)造方法
  • 2.WidgetCreateState
  • 3.State構(gòu)造方法
  • 4.StateinitState
  • 5.didChangeDependencies方法(改變依賴關(guān)系);依賴(共享數(shù)據(jù))的InheritedWidget發(fā)生變化之后井辆,didChangeDependencies才會調(diào)用
  • 6.StateBuild ,當(dāng)調(diào)用setState方法关筒。會重新調(diào)用Build進(jìn)行渲染,setState方法內(nèi)部主要是利用_element(本質(zhì)是就是context對象) 調(diào)用 markNeedsBuild
  • 7.當(dāng)Widget銷毀的時候調(diào)用Statedispose

2.3setState實現(xiàn)

  @protected
  void setState(VoidCallback fn) {
    assert(fn != null);
    assert(() {
      if (_debugLifecycleState == _StateLifecycle.defunct) {
        throw FlutterError.fromParts(<DiagnosticsNode>[
          ErrorSummary('setState() called after dispose(): $this'),
          ErrorDescription(
            'This error happens if you call setState() on a State object for a widget that '
            'no longer appears in the widget tree (e.g., whose parent widget no longer '
            'includes the widget in its build). This error can occur when code calls '
            'setState() from a timer or an animation callback.',
          ),
          ErrorHint(
            'The preferred solution is '
            'to cancel the timer or stop listening to the animation in the dispose() '
            'callback. Another solution is to check the "mounted" property of this '
            'object before calling setState() to ensure the object is still in the '
            'tree.',
          ),
          ErrorHint(
            'This error might indicate a memory leak if setState() is being called '
            'because another object is retaining a reference to this State object '
            'after it has been removed from the tree. To avoid memory leaks, '
            'consider breaking the reference to this object during dispose().',
          ),
        ]);
      }
      if (_debugLifecycleState == _StateLifecycle.created && !mounted) {
        throw FlutterError.fromParts(<DiagnosticsNode>[
          ErrorSummary('setState() called in constructor: $this'),
          ErrorHint(
            'This happens when you call setState() on a State object for a widget that '
            "hasn't been inserted into the widget tree yet. It is not necessary to call "
            'setState() in the constructor, since the state is already assumed to be dirty '
            'when it is initially created.',
          ),
        ]);
      }
      return true;
    }());
    final Object? result = fn() as dynamic;
    assert(() {
      if (result is Future) {
        throw FlutterError.fromParts(<DiagnosticsNode>[
          ErrorSummary('setState() callback argument returned a Future.'),
          ErrorDescription(
            'The setState() method on $this was called with a closure or method that '
            'returned a Future. Maybe it is marked as "async".',
          ),
          ErrorHint(
            'Instead of performing asynchronous work inside a call to setState(), first '
            'execute the work (without updating the widget state), and then synchronously '
            'update the state inside a call to setState().',
          ),
        ]);
      }
      // We ignore other types of return values so that you can do things like:
      //   setState(() => x = 3);
      return true;
    }());
    _element!.markNeedsBuild();
  }

setState方法其實核心就是最后一句_element!.markNeedsBuild();

  BuildContext get context {
    assert(() {
      if (_element == null) {
        throw FlutterError(
          'This widget has been unmounted, so the State no longer has a context (and should be considered defunct). \n'
          'Consider canceling any active work during "dispose" or using the "mounted" getter to determine if the State is still active.',
        );
      }
      return true;
    }());
    return _element!;
  }
  StatefulElement? _element;

由上面的源碼可以得出_element其實就是Statebulid方法中的context

3.Flutter渲染原理

實際上,Flutter的UI繪制包含了三個元素杯缺,Widget蒸播,ElementRenderObject。這三個元素分別組成了三棵樹:Widget 樹,Element 樹和 RenderObject樹,在Flutter渲染的流程中Flutter引擎渲染是針對Render樹中的對象進(jìn)行渲染

Flutter三棵樹

系統(tǒng)啟動時袍榆,runApp方法會被調(diào)用胀屿,Flutter會從最外層的Widget去遍歷創(chuàng)建一顆Widget樹;

  • 每一個Widget創(chuàng)建出來都會調(diào)用createElement方法創(chuàng)建一個Element對象
  • Element加入到Element樹中包雀,形成Element
  • Element通過mount方法調(diào)用createRenderObject創(chuàng)建RenderObject對象,并形成相應(yīng)的RenderObject

StatelessElement 繼承 ComponentElement主要調(diào)用build方法宿崭,并且將自己(Element)傳遞出去

StatefulElement 繼承 ComponentElement,調(diào)用creatState方法,創(chuàng)建state,將Widget賦值給State對象,調(diào)用statebuild方法才写,并且將自己(Element)傳出去

??注意
只有繼承自RenderObjectWidgetWidget才能創(chuàng)建RenderObject并加入RenderObject樹劳曹,被渲染

3.1三棵樹的作用

  • Widget樹:配置信息,用來描述UI特征琅摩,比如尺寸多大,顏色是什么锭硼,位置在哪里
  • Element樹:element是widget的實際實例房资,它同時持有了widget和renderObject的引用,用來決定是否進(jìn)行UI更新檀头。
  • RenderObject樹:UI更新的執(zhí)行者轰异,保存了元素的大小,布局等信息暑始。它才是真正調(diào)用渲染引擎去進(jìn)行更新的對象
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末搭独,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子廊镜,更是在濱河造成了極大的恐慌牙肝,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嗤朴,死亡現(xiàn)場離奇詭異配椭,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)雹姊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進(jìn)店門股缸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人吱雏,你說我怎么就攤上這事敦姻。” “怎么了歧杏?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵镰惦,是天一觀的道長。 經(jīng)常有香客問我得滤,道長陨献,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任懂更,我火速辦了婚禮眨业,結(jié)果婚禮上急膀,老公的妹妹穿的比我還像新娘。我一直安慰自己龄捡,他們只是感情好卓嫂,可當(dāng)我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著聘殖,像睡著了一般晨雳。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上奸腺,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天餐禁,我揣著相機(jī)與錄音,去河邊找鬼突照。 笑死帮非,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的讹蘑。 我是一名探鬼主播末盔,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼座慰!你這毒婦竟也來了陨舱?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤版仔,失蹤者是張志新(化名)和其女友劉穎游盲,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蛮粮,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡背桐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蝉揍。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片链峭。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖又沾,靈堂內(nèi)的尸體忽然破棺而出弊仪,到底是詐尸還是另有隱情,我是刑警寧澤杖刷,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布励饵,位于F島的核電站,受9級特大地震影響滑燃,放射性物質(zhì)發(fā)生泄漏役听。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望典予。 院中可真熱鬧甜滨,春花似錦、人聲如沸瘤袖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽捂敌。三九已至艾扮,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間占婉,已是汗流浹背泡嘴。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留逆济,地道東北人磕诊。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像纹腌,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子滞磺,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,601評論 2 353