Flutter开发1:Widget与生命周期

什么是Widget

Flutter中几乎所有的对象都是一个Widget,这与原生开发中“控件”概念稍有不同,Flutter中的Widget表示一切与UI框架相关的对象,例如:手势检测 GestureDetector,而原生开发中的Widget控件通常仅仅指UI布局中的各种控件,不包含Flutter中的功能型Widget。

标识符:Key

Flutter 是响应式框架,每次刷新 UI 的时候,都会重新构建新的 Widget树,并和之前的 Widget树进行对比,计算出变化的部分,这个计算过程就是diff,在 diff 过程中,如果能提前知道哪些 Widget 没有变化,就能提高 diff 的性能,这时候就需要使用到标识符。

给 Widget 添加一个唯一的标识符,然后在 Widget树 的 diff 过程中查看刷新前后的 Widget树,如果标识符相同,则说明 Widget 没有变化,否则说明 Widget 有变化。

这个标识符就是Flutter 中的Key属性,所有 Widget 都有 Key 属性

Key有两种类型:

  • Local Key(局部Key)
  • Global Key(全局Key)

什么是StatelessWidget

它是一个比较简并继承自Widget类的一个类,常在build方法中通过嵌套其它Widget来构建UI。当我们需要组合并封装多个Widget控件,且不需要维护数据状态时,可以自定义Widget并继承该类。它最大的特点是仅表示当前一帧的页面,当页面动态变化时,每次都会重建数据。

需要注意,它的内部成员变量是immutable的,通常需要使用final修饰。

什么是 StatefulWidget

它也是继承自Widget类,不同的是一个StatefulWidget类就会对应一个State类。State表示与其对应的StatefulWidget要维护的状态,且State中存在与原生开发中类似的生命周期回调。

State 类有两个功能:

  • build() 方法创建 UI
  • setState() 方法刷新 UI

调用setState()方法并在其中修改数据的值,会触发 State 的 build() 方法,重建 Widget,重建时会重新绑定数据,这时数据已变化,从而达到更新页面的目的。

State 中还有三个重要的成员变量

  • widget 通过该变量可访问 StatefulWidget 中定义的成员属性
  • context 用于获取当前 StatefulWidget 中的上下文
  • mounted 判断当前 State 是否已加载到树中。在State 对象创建之后,initState() 调用之前,框架会将 State 对象加载到树中,此时 mounted 会变为 true,当 State dispose 之后,mounted 就为 false。因此,在setState() 调用前可判断 mounted 的值以避免异常,mounted 为 false 时调用setState()会报错。
if(mounted){
    setState((){
        // :TODO
    })
}

StatelessWidget 和 StatefulWidget的区别

  • StatelessWidget 是 UI 不可变化的 Widget,创建完后 UI 就不能发生变化;
  • StatefulWidget 是 UI 可变化的 Widget,并存在生命周期,创建完后 UI 可以更改。通常的,一个单独页面的根Widget应当使用StatefulWidget 包裹,存在并需要封装动画时,也需要使用StatefulWidget封装控件。

widget生命周期回调

StatefulWidget 生命周期回调

  • initState 当Widget 第一次插入到 Widget树时被调用,对于每一个State对象,该回调只会调用一次,所以通常会在回调中做一些初始化。覆写此方法时,应在调用super.iniState()之后
  • didChangeDependencies 创建时在initState 之后被调用,或者当State对象的依赖发生变化时调用,子类很少覆写
  • build 构建该Widget 表示的UI元素。此方法在不同情况下被调用:
    1.调用initState之后
    2.调用didUpdateWidget之后
    3.调用setState之后
    4.当State对象的依赖更改(didChangeDependencies)之后
    5.当State对象从树中一个位置移除后(调用deactivate)又重新插入到树的其它位置时调用
  • didUpdateWidget 当Widget 的状态发生改变时调用,例如调用setState
  • deactivate 当State对象从树中被移除时,会调用此回调。如果移除后没有重新插入到树中则紧接着会调用dispose方法,如果覆写此方法,应在调用super.deactivate()之前
    dispose 当State对象从树中被永久移除时调用。通常在此回调中释放资源,如果覆写此方法,应在调用super.dispose()之前
class _MyHomePageState extends State {
//定义变量区域
  final GlobalKey _gk = GlobalKey();
  int count = 0;

//定义其他函数,放前面或者后面都可以
  void _showHint() {

  }

//widget生命周期函数如下
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    debugPrint('initState');
  }

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

  @override
  Widget build(BuildContext ctx) {
    // this.context;
    return Scaffold();
  }

  @override
  void didUpdateWidget(covariant MyHomePage oldWidget) {
    super.didUpdateWidget(oldWidget);
    debugPrint('didUpdateWidget');
  }

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

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

App 的生命周期

除了Widget,App本身也存在生命周期,这类似原生App的生命周期,主要指进入app,按home键等系统级的操作。

要监听系统级的App生命周期回调,需要在页面的State类上混入WidgetsBindingObserver类,并实现didChangeAppLifecycleState回调方法
注意:不要忘了注册和移除监听器,否则不生效

class _MyAppState extends State with WidgetsBindingObserver{

  @override
  void initState() {
    super.initState();
    /// 注册监听器
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    switch (state) {
      case AppLifecycleState.resumed:
        break;
      case AppLifecycleState.inactive: 
        break;
      case AppLifecycleState.paused: 
        break;
      case AppLifecycleState.detached: 
        break;
    }
  }

  @override
  void dispose() {
    /// 移除监听器
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }
}

AppLifecycleState提供四种状态

  • resumed 应用处于前台,可见可交互
  • inactive应用处于非活动状态。在 iOS 上,当在通话、响应TouchID请求、进入应用切换器或控制中心时,应用会过渡到这个状态。在Android上,当其他活动被聚焦时,例如分屏应用、电话呼叫、画中画应用、弹出系统对话框时,应用会过渡到这个状态
  • paused应用不可见,处于后台运行时处于该状态
  • detached Flutter引擎第一次初始化时正在加载视图,或在视图因Navigator.pop 而被摧毁后时,处于该状态

你可能感兴趣的:(Flutter开发1:Widget与生命周期)