Flutter的一生

猩程變發表於2019-07-09

說明: 本篇文章已授權微信公眾號 Flutter那些事 獨家釋出,未經授權,嚴禁轉載!

1. 前言 在初學新技術之前,我們總會要從最基本的東西瞭解起來,就好比當接觸Android的時候,我們學四大元件都要學好久,是否還記得在Android的生命週期?首先讓我們回顧下Android中的生命週期

Android生命週期
關於這個就不在多說了,常用場景總結下:

1.啟動Activity:系統會先呼叫onCreate方法,然後呼叫onStart方法,最後呼叫onResume,Activity進入執行狀態。

2.當前Activity被其他Activity覆蓋其上或被鎖屏:系統會呼叫onPause方法,暫停當前Activity的執行。

3.當前Activity由被覆蓋狀態回到前臺或解鎖屏:系統會呼叫onResume方法,再次進入執行狀態。

4.當前Activity轉到新的Activity介面或按Home鍵回到主屏,自身退居後臺:系統會先呼叫onPause方法,然後呼叫onStop方法,進入停滯狀態。

5.使用者後退回到此Activity:系統會先呼叫onRestart方法,然後呼叫onStart方法,最後呼叫onResume方法,再次進入執行狀態。

6.當前Activity處於被覆蓋狀態或者後臺不可見狀態,即第2步和第4步,系統記憶體不足,殺死當前Activity,而後使用者退回當前Activity:再次呼叫onCreate方法、onStart方法、onResume方法,進入執行狀態。

7.使用者退出當前Activity:系統先呼叫onPause方法,然後呼叫onStop方法,最後呼叫onDestory方法,結束當前Activity。
複製程式碼

emmm,相信小夥伴們現在應該記憶起來了吧,前戲好了,進入主題,聊聊我們今天的主人公"State"

2. Widget概念 在我們的主人公出場前,先認識下他的小夥伴

Flutter中幾乎所有的物件都是一個Widget,與原生開發中“控制元件”不同的是,
Flutter中的widget的概念更廣泛,它不僅可以表示UI元素,也可以表示一些功能性的元件如:用於手勢檢測的 GestureDetector widget、用於應用主題資料傳遞的Theme等等。
而原生開發中的控制元件通常只是指UI元素
複製程式碼

3. State的引入

  • StatelessWidget(用於不需要維護狀態的場景)
abstract class StatelessWidget extends Widget
複製程式碼
  • StatefulWidget(用於需要維護狀態的場景)
abstract class StatefulWidget extends Widget
複製程式碼

從上述的程式碼中我們看到他們都繼承了一個東西Widget,那就先簡單的看下這個類

@immutable
abstract class Widget extends DiagnosticableTree {
  const Widget({ this.key });
  final Key key;

  @protected
  Element createElement();

  @override
  String toStringShort() {
    return key == null ? '$runtimeType' : '$runtimeType-$key';
  }

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.defaultDiagnosticsTreeStyle = DiagnosticsTreeStyle.dense;
  }

  static bool canUpdate(Widget oldWidget, Widget newWidget) {
    return oldWidget.runtimeType == newWidget.runtimeType
        && oldWidget.key == newWidget.key;
  }
}
複製程式碼

上述程式碼中有一個我們很常見的方法,每次在繼承的時候都需要重寫的一個方法

  @override
  StatefulElement createElement() => StatefulElement(this);
複製程式碼

繼續跟蹤StatefulElement發現存在一個*widget.createState()*方法,發現了就要繼續,寧殺錯,莫放過

class StatefulElement extends ComponentElement {
  /// Creates an element that uses the given widget as its configuration.
  StatefulElement(StatefulWidget widget)
      : _state = widget.createState(),
        super(widget) {
   .....
    assert(_state._element == null);
    _state._element = this;
    assert(_state._widget == null);
    _state._widget = widget;
    assert(_state._debugLifecycleState == _StateLifecycle.created);
  }

複製程式碼

點選createState方法我們終於找到了今天的主人公,沒錯,就是它,State,跑不掉了。

  @protected
  State createState();
複製程式碼
  1. 生命週期 到了現在這一步,我們已經找到想要的了,正如前面所說,Android有自己的生命週期,那麼作為Flutter也有自己獨特的生命週期
    Flutter生命週期
    嗯,我一眼就看到了initState這個方法,還記得在網路請求的時候亦或是變數的初始化,總是要寫到這個方法裡面
  @override
 void initState() {
   // TODO: implement initState
   super.initState();
   _loadItemPage();
 }
複製程式碼

我們可以將上述方法分為三個部分進行描述,見下圖:

在這裡插入圖片描述
大致可以看成三個階段

  • 初始化(插入渲染樹)
  • 建構函式
不屬於生命週期,因為這個時候State的widget屬性為空,此時無法在建構函式中訪問widget屬性
複製程式碼
  • initState
 /// Called when this object is inserted into the tree.
  
這個函式在生命週期中只呼叫一次。這裡可以做一些初始化工作,比如初始化State的變數
複製程式碼
  • didChangeDependencies
 /// Called when a dependency of this [State] object changes.
 
這個函式會緊跟在initState之後呼叫
複製程式碼
  • 狀態改變(在渲染樹中存在)
  • didUpdateWidget
/// Called whenever the widget configuration changes.
 
當元件的狀態改變的時候就會呼叫didUpdateWidget,比如呼叫了setStat
複製程式碼
  • 銷燬(從渲染樹種移除)
  • deactivate
/// Called when this object is removed from the tree.
 
在dispose之前,會呼叫這個函式。
複製程式碼
  • dispose
/// Called when this object is removed from the tree permanently.
 
一旦到這個階段,元件就要被銷燬了,這個函式一般會移除監聽,清理環境。
複製程式碼

這個函式在生命週期中只呼叫一次。這裡可以做一些初始化工作,比如初始化State的變數。

大體這樣吧,最後來個圖表總結下

階段 呼叫次數 是否支援setState
建構函式 1
initState 1 支援但無效(使用setState和不使用一樣)
didChangeDependencies >=1 支援但無效
didUpdateWidget >=1 支援但無效
deactivate >=1
dispose 1
  1. 示例分析 可能有人會說,bb了那麼久,毛都沒看到一根,所以講了這麼多,不來點實際的怎麼對的住之前的bb呢?來人啊,上程式碼
import 'package:flutter/material.dart';

class LifeState extends StatefulWidget {
  @override
  _lifeStates createState() => _lifeStates();
}

class _lifeStates extends State<LifeState> {
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    print('initState');
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    print(state.toString());
  }

  @override
  void didChangeDependencies() {
    // TODO: implement didChangeDependencies
    super.didChangeDependencies();
    print('didChangeDependencies');
  }

  @override
  void didUpdateWidget(LifeState oldWidget) {
    super.didUpdateWidget(oldWidget);
    print('didUpdateWidget');
  }

  @override
  Widget build(BuildContext context) {
    print('build');
    // TODO: implement build
    return MaterialApp(
      home: Center(
          child: GestureDetector(
        child: new Text('lifeCycle'),
        onTap: () {
          Navigator.of(context)
              .push(new MaterialPageRoute(builder: (BuildContext c) {
            return new Text('sdfs');
          }));
        },
      )),
    );
  }

  @override
  void reassemble() {
    // TODO: implement reassemble
    super.reassemble();
    print('reassemble');
  }

  @override
  void deactivate() {
    // TODO: implement deactivate
    super.deactivate();
    print('deactivate');
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    print('dispose');
  }
}

複製程式碼

測試結果

  1. 建立widget
initState
didChangeDependencies
build
複製程式碼
  1. 退出頁面
deactivate
dispose
複製程式碼
  1. 點選熱載入按鈕
reassemble
didUpdateWidget
build
複製程式碼
  1. app從顯示到後臺(home鍵)
AppLifecycleState.inactive
AppLifecycleState.paused
複製程式碼
  1. app從後臺回到前臺
AppLifecycleState.inactive
AppLifecycleState.resumed
複製程式碼

相關文章