Flutter state和App生命周期介紹

一、State生命周期介紹
Flutter中一切皆widget挑格。widget分為無狀態(tài)和有狀態(tài)兩種咙冗,分別是StatelessWidget和StatefulWidget。無狀態(tài)組件只加載一次漂彤,無生命周期雾消。有狀態(tài)組件可以根據(jù)數(shù)據(jù)來更新灾搏,下面介紹一下有狀態(tài)組件的生命周期。

Flutter的生命周期包含一下幾個(gè)階段:

  • CreateState 該函數(shù)為StatefulWidget創(chuàng)建State時(shí)調(diào)用的方法仪或,當(dāng)StatefulWidget被調(diào)用時(shí)候會(huì)立即調(diào)用此方法确镊。
  • initState 該方法為State初始化調(diào)用,因此在此期間可以執(zhí)行變量的初始化范删,還可以進(jìn)行與服務(wù)端的初始化蕾域,獲取到服務(wù)端數(shù)據(jù)之后調(diào)用setState方法更新組件。
  • didChangeDependencies 該函數(shù)是在該組件依賴的全局State發(fā)生變化的時(shí)候調(diào)用到旦。
  • build 該函數(shù)主要是渲染W(wǎng)idget旨巷,會(huì)被調(diào)用多次,最好只做返回Widget相關(guān)的事情添忘。
  • reassemble 只要是提供開發(fā)階段使用采呐,只有在debug模式下熱重載才會(huì)調(diào)用「槠铮可以添加一些代碼來調(diào)試斧吐。
  • didUpdateWidget 此方法在組件重新構(gòu)建,比如熱更新仲器,父組件發(fā)生Build時(shí)候調(diào)用此方法煤率,其次此方法會(huì)導(dǎo)致本組件的build方法被調(diào)用。
  • deactivate 在組件被移除時(shí)候調(diào)用乏冀,如果組件被移除蝶糯,未被插入到其他組件。那么會(huì)調(diào)用dispose永久移除辆沦。


    flutter生命周期.png
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

class Lifecycle extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'lifecycle',
      home: Scaffold(
        appBar: AppBar(
          title: Text('lifecyle'),
        ),
        body: Center(
          child: LifecycleWidget(),
        ),
      ),
    );
  }
}

class LifecycleWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    print('createState');
    return LifecycleState();
  }
}

class LifecycleState extends State<LifecycleWidget> {
  int count = 1;
  String name = 'test';

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

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

  @override
  void didUpdateWidget(LifecycleWidget oldWidget) {
    count++;
    print('didUpdateWidge  $count');
    super.didUpdateWidget(oldWidget);
  }

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

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

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

  void changeName(){
    setState(() {
      print('set State');
      this.name = 'flutter';
    });
  }


  @override
  Widget build(BuildContext context) {
    print('buid');
    return Column(
      children: <Widget>[
        FlatButton(
          child: Text('$name  $count'),
          onPressed: changeName,
        )
      ],
    );
  }


}

打印結(jié)果

I/flutter ( 1431): createState
I/flutter ( 1431): initState
I/flutter ( 1431): didchangeDependencies
I/flutter ( 1431): buid
I/flutter ( 1431): reassemble
I/flutter ( 1431): didUpdateWidge  2
I/flutter ( 1431): buid

點(diǎn)擊按鈕

I/flutter ( 1604): set State
I/flutter ( 1604): buid

第一次build了兩次昼捍,正式模式下是不會(huì)這樣的,build很消耗性能的。

setState會(huì)引起build ,而buid會(huì)重新更新組件控妻,并且他的子組件也會(huì)更新蚜印。會(huì)調(diào)用子組件的didUpdateWidget和build方法。

I/flutter ( 1956): set State
I/flutter ( 1956): buid
I/flutter ( 1956): sub didUpdateWidget
I/flutter ( 1956): sub  build

二、App生命周期的介紹
app的啟動(dòng)到退出的全過程。在Flutter中可以通過WidgetsBindingObserver來實(shí)現(xiàn)監(jiān)聽。


abstract class WidgetsBindingObserver {
  //頁面pop
  Future<bool> didPopRoute() => Future<bool>.value(false);
  //頁面push
  Future<bool> didPushRoute(String route) => Future<bool>.value(false);
  //系統(tǒng)窗口相關(guān)改變回調(diào)团赁,如旋轉(zhuǎn)
  void didChangeMetrics() { }
  //文本縮放系數(shù)變化
  void didChangeTextScaleFactor() { }
  //系統(tǒng)亮度變化
  void didChangePlatformBrightness() { }
  //本地化語言變化
  void didChangeLocales(List<Locale> locale) { }
  //App生命周期變化
  void didChangeAppLifecycleState(AppLifecycleState state) { }
  //內(nèi)存警告回調(diào)
  void didHaveMemoryPressure() { }
  //Accessibility相關(guān)特性回調(diào)
  void didChangeAccessibilityFeatures() {}
}

重點(diǎn)介紹下didChangeAppLifecycleState這個(gè)回調(diào)方法。

AppLifecycleState是個(gè)枚舉谨履,有三個(gè)狀態(tài):

  • resume 可見欢摄,能響應(yīng)操作
  • inactive 處于不可活動(dòng)狀態(tài),無法處理用戶響應(yīng)
  • paused 不可見笋粟,不能響應(yīng)用戶輸入怀挠,但在后臺(tái)繼續(xù)活動(dòng)中析蝴。

寫一個(gè)demo測(cè)試一下打印


class _MyHomePageState extends State<MyHomePage>  with WidgetsBindingObserver{//這里你可以再回顧下,第7篇文章“函數(shù)绿淋、類與運(yùn)算符:Dart是如何處理信息的闷畸?”中關(guān)于Mixin的內(nèi)容
...
  @override
  @mustCallSuper
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);//注冊(cè)監(jiān)聽器
  }
  @override
  @mustCallSuper
  void dispose(){
    super.dispose();
    WidgetsBinding.instance.removeObserver(this);//移除監(jiān)聽器
  }
  @override
  void didChangeAppLifecycleState(AppLifecycleState state) async {
    print("$state");
    if (state == AppLifecycleState.resumed) {
      //do sth
    }
  }
}

我們?cè)囍袚Q一下前、后臺(tái)吞滞,觀察控制臺(tái)輸出的 App 狀態(tài)佑菩,可以發(fā)現(xiàn):從后臺(tái)切入前臺(tái),控制臺(tái)打印的 App 生命周期變化如下: AppLifecycleState.paused->AppLifecycleState.inactive->AppLifecycleState.resumed裁赠;從前臺(tái)退回后臺(tái)殿漠,控制臺(tái)打印的 App 生命周期變化則變成了:AppLifecycleState.resumed->AppLifecycleState.inactive->AppLifecycleState.paused∨謇蹋可以看到绞幌,App 前后臺(tái)切換過程中打印出的狀態(tài)是完全符合預(yù)期的。

App切換前后臺(tái)狀態(tài)變化示意圖.png

三一忱、幀繪制回調(diào)
以安卓為例莲蜘,有時(shí)候我們需要使用view.post等待渲染完成之后去做一些操作。
在flutter中帘营,可以監(jiān)聽幀的回調(diào)菇夸,有兩種:一種是只回調(diào)一次,一種是每一幀都回調(diào)仪吧。

  • 單幀回調(diào):通過addPostFrameCallback回調(diào)來監(jiān)聽當(dāng)前幀繪制完成

WidgetsBinding.instance.addPostFrameCallback((_){
    print("單次Frame繪制回調(diào)");//只回調(diào)一次
  });
  • 多幀回調(diào):通過addPersistentFrameCallback回調(diào)監(jiān)聽每一次幀繪制完成的回調(diào),可以用來做幀的檢測(cè)鞠眉。

WidgetsBinding.instance.addPersistentFrameCallback((_){
  print("實(shí)時(shí)Frame繪制回調(diào)");//每幀都回調(diào)
});
Flutter 頁面之間的跳轉(zhuǎn)監(jiān)聽薯鼠,有時(shí)候通過上面幾種方式是無法監(jiān)聽到的,我們可以通過頁面監(jiān)聽可以做到械蹋,具體見我另一篇文章《Flutter 監(jiān)聽頁面切換》
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末出皇,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子哗戈,更是在濱河造成了極大的恐慌郊艘,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件唯咬,死亡現(xiàn)場(chǎng)離奇詭異纱注,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)胆胰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門狞贱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蜀涨,你說我怎么就攤上這事瞎嬉⌒保” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵氧枣,是天一觀的道長沐兵。 經(jīng)常有香客問我,道長便监,這世上最難降的妖魔是什么扎谎? 我笑而不...
    開封第一講書人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮茬贵,結(jié)果婚禮上簿透,老公的妹妹穿的比我還像新娘。我一直安慰自己解藻,他們只是感情好老充,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著螟左,像睡著了一般啡浊。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上胶背,一...
    開封第一講書人閱讀 51,287評(píng)論 1 301
  • 那天巷嚣,我揣著相機(jī)與錄音,去河邊找鬼钳吟。 笑死廷粒,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的红且。 我是一名探鬼主播坝茎,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼暇番!你這毒婦竟也來了嗤放?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤壁酬,失蹤者是張志新(化名)和其女友劉穎次酌,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體舆乔,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡岳服,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了希俩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片派阱。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖斜纪,靈堂內(nèi)的尸體忽然破棺而出贫母,到底是詐尸還是另有隱情文兑,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布腺劣,位于F島的核電站绿贞,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏橘原。R本人自食惡果不足惜籍铁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望趾断。 院中可真熱鬧拒名,春花似錦、人聲如沸芋酌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽脐帝。三九已至同云,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間堵腹,已是汗流浹背炸站。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留疚顷,地道東北人旱易。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像腿堤,于是被迫代替她去往敵國和親咒唆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354