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)用??梢蕴砑右恍┐a來調(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 {
  //頁(yè)面pop
  Future<bool> didPopRoute() => Future<bool>.value(false);
  //頁(yè)面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() { }
  //本地化語(yǔ)言變化
  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)聽?zhēng)幕卣{(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 頁(yè)面之間的跳轉(zhuǎn)監(jiān)聽,有時(shí)候通過上面幾種方式是無法監(jiān)聽到的,我們可以通過頁(yè)面監(jiān)聽可以做到,具體見我另一篇文章《Flutter 監(jiān)聽頁(yè)面切換》
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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