最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Flutter有狀態(tài)組件StatefulWidget生命周期詳解

 更新時間:2023年01月13日 09:04:06   作者:半點橘色  
這篇文章主要為大家介紹了Flutter有狀態(tài)組件StatefulWidget生命周期詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

1、StatefulWidget的背后

flutter開發(fā)過程中,我們經常會用到兩個組件StatelessWidget和StatefulWidget。前者為無狀組件,后者為有狀態(tài)組件,無狀態(tài)組件通常在創(chuàng)建后內部的數據無法改變,而有狀態(tài)組件可以維持內部的數據狀態(tài),適合動態(tài)組件使用。

/// 無狀態(tài)組件的定義
class MyApp extends StatelessWidget {}
/// 有狀態(tài)狀態(tài)組件的定義
class MyApp extends StatefullWidget {
  @override
  State<StatefulWidget> createState() => _MyApp();
}
class _MyApp extends State<MyApp> {}

定義無狀態(tài)組件相對簡單,只需要繼承StatelessWidget即可,而有狀態(tài)組件需要兩個類來實現,首先是繼承StatefullWidget,然后重寫createState方法,返回State的實現類。

剛始我不明白StatefullWidget為何要通過重寫createState的方式來實現,后來通過對StatelessWidget的深入,我漸漸的理解了其中的用意。

首先,StatelessWidget和StatefulWidget都的父類來自Widget,而Widget在定義過程中使用了dart的注解@immutable。

@immutable的作用根據官方的解釋:被@immutable注解標明的類或者子類都必須是不可變的。

也就是說,繼承了StatelessWidget和StatefullWidget的組件都必須為常量組件,可以使用const修飾,而它的構造函數和成員屬性需要是常量,不可變的。

class MyApp extends StatelessWidget {
  /// 常量屬性,不加final會警告
  final String? title;
  const MyApp({Key? key, this.title}) : super(key: key);
}
/// or
class MyApp extends StatefulWidget {
  /// 常量屬性,不加final會警告
  final String? title;
  const MyApp({Key? key, this.title}) : super(key: key);
  @override
  State<StatefulWidget> createState() => _MyApp();
}
/// 調用時可以加const
const MyApp()

StatelessWidget自然沒什么問題,本身它就是無狀態(tài)組件,創(chuàng)建出來內部數據不會改變,符合@immutable的定義。而StatefullWidget不同,作為有狀態(tài)組件,需要維持自身的成員屬性可變,不能是一個常量。那如何解決呢?就是通過State來保持狀態(tài),因為它并不繼承Widget,不受@immutable的影響,內部成員可以定義成變量。

還有個問題,為什么Widget非要使用@immutable來注釋?

這一切的出發(fā)點都是為了減少性能的損耗,提高Widget構建效率。因為常量定義的類,不會重復構建,可以大大提升運行速度,只要明白這一點,就能解了StatefulWidget這樣設計的意義。

2、StatefulWidget的生命周期

StatefulWidget通過State來管理狀態(tài),同時也提供了相應的生命周期函數,如initState、didUpdateWidget、dispose等,我們只需要重寫這些函數,StatefulWidget在執(zhí)行過程中會在合適的時機調用。

StatefulWidget的生命周期可以分為創(chuàng)建階段、更新階段和銷毀階段,下面我們結合一個示例來看下它的執(zhí)行過程。

/// StatefulWidget demo
import 'package:flutter/material.dart';
void main() {
  runApp(const MyApp());
}
class ColorInheritedWidget extends InheritedWidget {
  final Color color;
  const ColorInheritedWidget({
    Key? key,
    required this.color,
    required Widget child,
  }) : super(key: key, child: child);
  @override
  bool updateShouldNotify(covariant ColorInheritedWidget oldWidget) {
    return oldWidget.color != color;
  }
  static ColorInheritedWidget? of(BuildContext context) =>
      context.dependOnInheritedWidgetOfExactType<ColorInheritedWidget>();
}
class MyApp extends StatefulWidget {
  final String? title;
  const MyApp({Key? key, this.title}) : super(key: key);
  @override
  State<StatefulWidget> createState() {
    print('createState');
    return _MyApp();
  }
}
class _MyApp extends State<MyApp> {
  int value = 0;
  bool isDetach = false;
  Color color = Colors.red;
  @override
  void initState() {
    super.initState();
    print('initState');
  }
  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    print('didChangeDependencies');
  }
  @override
  void didUpdateWidget(covariant MyApp oldWidget) {
    super.didUpdateWidget(oldWidget);
    print('didUpdateWidget');
  }
  @override
  void deactivate() {
    super.deactivate();
    print('deactivate');
  }
  @override
  void dispose() {
    super.dispose();
    print('deactivate');
  }
  @override
  Widget build(BuildContext context) {
    print('build');
    return ColorInheritedWidget(
      color: color,
      child: MaterialApp(
        home: Scaffold(
          appBar: AppBar(
            title: const Text('StatefulWidget demo'),
          ),
          body: Column(
            children: [
              if (!isDetach) MyAppChild(value: value),
              MaterialButton(
                color: Colors.blue,
                onPressed: () {
                  value++;
                  setState(() {});
                },
                child: const Text('更新value'),
              ),
              MaterialButton(
                color: Colors.blue,
                onPressed: () {
                  color = color == Colors.red ? Colors.yellow : Colors.red;
                  setState(() {});
                },
                child: const Text('更新color'),
              ),
              MaterialButton(
                color: Colors.blue,
                onPressed: () {
                  isDetach = !isDetach;
                  setState(() {});
                },
                child: Text(isDetach ? '添加' : '移除'),
              )
            ],
          ),
        ),
      ),
    );
  }
}
class MyAppChild extends StatefulWidget {
  final int value;
  const MyAppChild({Key? key, required this.value}) : super(key: key);
  @override
  State<StatefulWidget> createState() {
    print('child-createState');
    return _MyAppChild();
  }
}
class _MyAppChild extends State<MyAppChild> {
  @override
  void initState() {
    super.initState();
    print('child-initState');
  }
  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    print('child-didChangeDependencies');
  }
  @override
  void didUpdateWidget(covariant MyAppChild oldWidget) {
    super.didUpdateWidget(oldWidget);
    print('child-didUpdateWidget');
  }
  @override
  void deactivate() {
    super.deactivate();
    print('child-deactivate');
  }
  @override
  void dispose() {
    super.dispose();
    print('child-dispose');
  }
  @override
  Widget build(BuildContext context) {
    print('child-build');
    return Container(
      width: 100,
      height: 100,
      color: ColorInheritedWidget.of(context)?.color,
      child: Text('${widget.value}'),
    );
  }
}

2.1創(chuàng)建階段

運行demo,首次渲染會打印出:

flutter: createState
flutter: initState
flutter: didChangeDependencies
flutter: build
flutter: child-createState
flutter: child-initState
flutter: child-didChangeDependencies
flutter: child-build

從這里我們可以看出,StatefulWidget組件執(zhí)行的順序createState -> initState -> didChangeDependencies -> build。

  • createState

Widget只是對組件信息的描述,而Element才是最終對Widget的實現。通過Element可以進行Widget的掛載和RenderObject的創(chuàng)建,最終實現UI的渲染。

flutter首幀渲染的過程中,會不斷向下遍歷Widget樹,通過cteateElememt創(chuàng)建Element實例,每創(chuàng)建一個Widget都會對應創(chuàng)建一個Element。例如創(chuàng)建StatefulWidget時會對應創(chuàng)建StatefulElement。

abstract class StatefulWidget extends Widget {
  const StatefulWidget({ Key? key }) : super(key: key);
  @override
  StatefulElement createElement() => StatefulElement(this);
  /// ...    
}

StatefulElement的構造函數中,執(zhí)行了StatefulWidget的createState方法,完成對State的調用。

class StatefulElement extends ComponentElement {
  StatefulElement(StatefulWidget widget)
      : _state = widget.createState(),
        super(widget) {
            state._element = this;
            state._widget = widget;
        }
  /// ...
}
  • initState

createState通過StatefulElement構造函數來創(chuàng)建,而initState在firstBuild方法中定義,firstBuild是首幀渲染的時候,通過StatefulElement實例的mount方法進行調用,firstBuild只會執(zhí)行一次,也就是說initState只會在Widget首次創(chuàng)建次調用。

通常我們會使用initState進行數據的初始化,也可以進行網絡請求操作。

/// StatefulElement
  @override
  void _firstBuild() {
    try {
      /// 調用initState
      final Object? debugCheckForReturnedFuture = state.initState() as dynamic;
    } finally {
      /// ...
    }
    /// 調用didChangeDependencies
    state.didChangeDependencies();
    /// 調用父級ComponentElement類的_firstBuild,再往上到Element的rebuild方法,最后觸發(fā)的是StatefulElement中的performRebuild方法。
    super._firstBuild();
  }
  @override
  void performRebuild() {
    /// _didChangeDependencies標記Element的依賴節(jié)點發(fā)生改變,didChangeDependencies會再次調用。
    if (_didChangeDependencies) {
      state.didChangeDependencies();
      _didChangeDependencies = false;
    }
    /// 調用ComponentElement中的performRebuild,最終觸發(fā)StatefulElement的build方法
    super.performRebuild();
  }
  @override
  Widget build() => state.build(this);

2.2更新階段

在State類中調用了setState方法,會解發(fā)組件update流程,它會對比新舊Element,將修改過的組件標記為臟元素。如果Widget依賴InheritedWidget的數據發(fā)現變化,會觸發(fā)didChangeDependencies函數,接著會調用子組件的update方法,在StatefulElement的update方法中執(zhí)行了didUpdateWidget,最后才執(zhí)行rebuild進行build的調用,完成UI的更新。

/// StatefulElement
  @protected
  @pragma('vm:prefer-inline')
  Element? updateChild(Element? child, Widget? newWidget, Object? newSlot) {
    /// ...
    final Element newChild;
    if (child != null) {
      bool hasSameSuperclass = true;
      if (hasSameSuperclass && child.widget == newWidget) {
        newChild = child;
      } else if (hasSameSuperclass && Widget.canUpdate(child.widget, newWidget)) {
        /// 更新邏輯會調用child的update方法
        child.update(newWidget);
        newChild = child;
      }  
    } 
    return newChild;
  }
/// StatefulElement
  @override
  void update(StatefulWidget newWidget) {
    super.update(newWidget);
    try {
      /// 調用state.didUpdateWidget
      final Object? debugCheckForReturnedFuture = state.didUpdateWidget(oldWidget) as dynamic;
    }
    /// 重新rebuild深入遍歷子組件
    rebuild();
  }

在demo中,點擊“更新value”按鈕,會打印出:

flutter: build
flutter: child-didUpdateWidget
flutter: child-build

從這里可以看出父組件setState時,會先走自身的build再觸發(fā)子組件的didUpdateWidget和build。

2.3銷毀階段

在demo中,點擊“移除”按鈕,會打印出:

flutter: build
flutter: child-deactivate
flutter: child-dispose

組件移除節(jié)點后會調用deactivate,如果該組件被移除節(jié)點,然后未被 插入到其他節(jié)點時,則會繼續(xù)調用 dispose 永久移除,并釋放組件資源。

總結:

1、StatefulWidget通過State來管理狀態(tài)數據,目的是為了保持StatefulWidget可常量創(chuàng)建,減少性能的損耗,提高Widget構建效率。

2、StatefulWidget創(chuàng)建階段生命周期先執(zhí)行順序createState -> initState -> didChangeDependencies -> build??梢栽趇nitState進行數據初始化、網絡請求操作。

3、StatefulWidget更新階段:build -> child didUpdateWidget -> child build。

4、StatefulWidget銷毀階段:build -> child deactivate -> child dispose。

以上就是Flutter有狀態(tài)組件StatefulWidget生命周期詳解的詳細內容,更多關于Flutter StatefulWidget生命周期的資料請關注腳本之家其它相關文章!

相關文章

最新評論

黑龙江省| 嘉义县| 汽车| 旬邑县| 双柏县| 右玉县| 资阳市| 白河县| 永清县| 宜昌市| 电白县| 安阳县| 锦屏县| 类乌齐县| 淳安县| 全椒县| 塔城市| 西青区| 鸡西市| 耿马| 泰顺县| 开原市| 新乐市| 日喀则市| 达孜县| 苍山县| 鄱阳县| 合阳县| 卫辉市| 蓝田县| 广宁县| 环江| 武宣县| 旺苍县| 旅游| 乐业县| 太原市| 福贡县| 东丰县| 开封市| 高碑店市|