Flutter-StatelessWidget和StatefulWidget

1. StatelessWidget

1.1 StatelessWidget通常是一些沒(méi)有狀態(tài)(State,也可以理解成data)需要維護(hù)的Widget:

  • 它們的數(shù)據(jù)通常是直接寫死;
  • 從parent widget中傳入的而且一旦傳入就不可以修改;
  • 從InheritedWidget獲取來(lái)使用的數(shù)據(jù);

1.2 StatelessWidget包含一個(gè)必須重寫的方法:build方法;

StatelessWidget沒(méi)辦法主動(dòng)去執(zhí)行build方法,當(dāng)我們使用的數(shù)據(jù)發(fā)生改變時(shí),build方法會(huì)被重新執(zhí)行
build方法什么情況下被執(zhí)行呢?:

  • 1)當(dāng)我們的StatelessWidget第一次被插入到Widget樹(shù)中時(shí)(也就是第一次被創(chuàng)建時(shí));
  • 2)當(dāng)我們的父Widget(parent widget)發(fā)生改變時(shí),子Widget會(huì)被重新構(gòu)建;
  • 3)如果我們的Widget依賴InheritedWidget的一些數(shù)據(jù),InheritedWidget數(shù)據(jù)發(fā)生改變時(shí);

2.有狀態(tài)的StatefulWidget

2.1 Flutter如何做到我們?cè)陂_(kāi)發(fā)中定義到Widget中的數(shù)據(jù)一定是final的呢?

@immutable
abstract class Widget extends DiagnosticableTree {
  const Widget({ this.key });
...省略代碼...
}

這里有一個(gè)很關(guān)鍵的東西@immutable

  • 我們似乎在Dart中沒(méi)有見(jiàn)過(guò)這種語(yǔ)法,這實(shí)際上是一個(gè) 注解,這涉及到Dart的元編程;
    官方有對(duì)@immutable進(jìn)行說(shuō)明:
  • 來(lái)源: https://api.flutter.dev/flutter/meta/immutable-constant.html
  • 說(shuō)明: 被@immutable注解標(biāo)明的類或者子類都必須是不可變的

結(jié)論: 定義到Widget中的數(shù)據(jù)一定是不可變的,需要使用final來(lái)修飾

2.2 如何存儲(chǔ)Widget狀態(tài)?

1)既然Widget是不可變,那么StatefulWidget如何來(lái)存儲(chǔ)可變的狀態(tài)呢?

  • StatelessWidget無(wú)所謂,因?yàn)樗锩娴臄?shù)據(jù)通常是直接定義完后就不修改的。
  • 但StatefulWidget需要有狀態(tài)(可以理解成變量)的改變,這如何做到呢?

2)Flutter將StatefulWidget設(shè)計(jì)成了兩個(gè)類:

  • 也就是你創(chuàng)建StatefulWidget時(shí)必須創(chuàng)建兩個(gè)類:
  • 一個(gè)類繼承自StatefulWidget,作為Widget樹(shù)的一部分;
  • 一個(gè)類繼承自State,用于記錄StatefulWidget會(huì)變化的狀態(tài),并且根據(jù)狀態(tài)的變化,構(gòu)建出新的Widget;

3)創(chuàng)建一個(gè)StatefulWidget,我們通常會(huì)按照如下格式來(lái)做:

  • 當(dāng)Flutter在構(gòu)建Widget Tree時(shí),會(huì)獲取State的實(shí)例,并且它調(diào)用build方法去獲取StatefulWidget希望構(gòu)建的Widget;
  • 那么,我們就可以將需要保存的狀態(tài)保存在MyState中,因?yàn)樗强勺兊模?/li>
class MyStatefulWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // 將創(chuàng)建的State返回
    return MyState();
  }
}

class MyState extends State<MyStatefulWidget> {
  @override
  Widget build(BuildContext context) {
    return <構(gòu)建自己的Widget>;
  }
}

2.3 思考:為什么Flutter要這樣設(shè)計(jì)呢?

這是因?yàn)樵贔lutter中,只要數(shù)據(jù)改變了Widget就需要重新構(gòu)建(rebuild)

2.4 StatefulWidget生命周期

1)Flutter小部件的生命周期:

  • StatelessWidget可以由父Widget直接傳入值,調(diào)用build方法來(lái)構(gòu)建,整個(gè)過(guò)程非常簡(jiǎn)單;
  • 而StatefulWidget需要通過(guò)State來(lái)管理其數(shù)據(jù),并且還要監(jiān)控狀態(tài)的改變決定是否重新build整個(gè)Widget;
  • 所以,我們主要討論StatefulWidget的生命周期,也就是它從創(chuàng)建到銷毀的整個(gè)過(guò)程;

2)那么StatefulWidget有哪些生命周期的回調(diào)呢?它們分別在什么情況下執(zhí)行呢?

  • 在下圖中,灰色部分的內(nèi)容是Flutter內(nèi)部操作的,我們并不需要手動(dòng)去設(shè)置它們;
  • 白色部分表示我們可以去監(jiān)聽(tīng)到或者可以手動(dòng)調(diào)用的方法;


    image.png
import 'package:flutter/material.dart';

main(List<String> args) {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("HelloWorld"),
        ),
        body: HomeBody(),
      ),
    );
  }
}


class HomeBody extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("HomeBody build");
    return MyCounterWidget();
  }
}


class MyCounterWidget extends StatefulWidget {
  
  MyCounterWidget() {
    print("執(zhí)行了MyCounterWidget的構(gòu)造方法");
  }
  
  @override
  State<StatefulWidget> createState() {
    print("執(zhí)行了MyCounterWidget的createState方法");
    // 將創(chuàng)建的State返回
    return MyCounterState();
  }
}

class MyCounterState extends State<MyCounterWidget> {
  int counter = 0;
  
  MyCounterState() {
    print("執(zhí)行MyCounterState的構(gòu)造方法");
  }

  @override
  void initState() {
    super.initState();
    print("執(zhí)行MyCounterState的init方法");
  }
  
  @override
  void didChangeDependencies() {
    // TODO: implement didChangeDependencies
    super.didChangeDependencies();
    print("執(zhí)行MyCounterState的didChangeDependencies方法");
  }

  @override
  Widget build(BuildContext context) {
    print("執(zhí)行執(zhí)行MyCounterState的build方法");
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              RaisedButton(
                color: Colors.redAccent,
                child: Text("+1", style: TextStyle(fontSize: 18, color: Colors.white),),
                onPressed: () {
                  setState(() {
                    counter++;
                  });
                },
              ),
              RaisedButton(
                color: Colors.orangeAccent,
                child: Text("-1", style: TextStyle(fontSize: 18, color: Colors.white),),
                onPressed: () {
                  setState(() {
                    counter--;
                  });
                },
              )
            ],
          ),
          Text("當(dāng)前計(jì)數(shù):$counter", style: TextStyle(fontSize: 30),)
        ],
      ),
    );
  }

  @override
  void didUpdateWidget(MyCounterWidget oldWidget) {
    super.didUpdateWidget(oldWidget);
    print("執(zhí)行MyCounterState的didUpdateWidget方法");
  }

  @override
  void dispose() {
    super.dispose();
    print("執(zhí)行MyCounterState的dispose方法");
  }
}

打印結(jié)果如下:

flutter: HomeBody build
flutter: 執(zhí)行了MyCounterWidget的構(gòu)造方法
flutter: 執(zhí)行了MyCounterWidget的createState方法
flutter: 執(zhí)行MyCounterState的構(gòu)造方法
flutter: 執(zhí)行MyCounterState的init方法
flutter: 執(zhí)行MyCounterState的didChangeDependencies方法
flutter: 執(zhí)行執(zhí)行MyCounterState的build方法

// 注意:Flutter會(huì)build所有的組件兩次(查了GitHub、Stack Overflow,目前沒(méi)查到原因)
flutter: HomeBody build
flutter: 執(zhí)行了MyCounterWidget的構(gòu)造方法
flutter: 執(zhí)行MyCounterState的didUpdateWidget方法
flutter: 執(zhí)行執(zhí)行MyCounterState的build方法

當(dāng)我們改變狀態(tài),手動(dòng)執(zhí)行setState方法后會(huì)

flutter: 執(zhí)行執(zhí)行MyCounterState的build方法

學(xué)習(xí)內(nèi)容來(lái)自Flutter從入門到實(shí)戰(zhàn)

最后編輯于
?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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