likes
comments
collection
share

Flutter 3.13 生命周期新组件 AppLifecycleListener

作者站长头像
站长
· 阅读数 3

Flutter 3.13 上周正式发布,官方公告

Flutter 3.13引入了一种新的处理生命周期的方式:AppLifecycleListener,相比旧版本的处理,它更加灵活写法也更加简洁,今天就来介绍一下这个新组件。

旧版本的处理

在旧版本中,如果我们要监听应用的生命周期,一般会在State上 mixin 一个 WidgetsBindingObserver,然后在initState时加上监听,在dispose时移除监听。

class _MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver {
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }
  
  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    // logic
  }
  
  @override
  void dispose() {
    super.dispose();
    WidgetsBinding.instance.removeObserver(this);
  }
}

WidgetsBindingObserver 有一些弊端,它没有保存当前的生命周期状态,如果要增加状态变化时的一些处理,还需要自己额外定义当前的状态_currentLifecycleState,在didChangeAppLifecycleState方法中判断状态是否改变,当改变时触发onStateChange

AppLifecycleListener

AppLifecycleListener是基于WidgetsBindingObserver的封装,它在初始化时会自动进行生命周期的监听,同时在didChangeAppLifecycleState中对生命周期进行了预处理判断,我们只需要在构造函数中传入我们关心的生命周期回调处理即可

AppLifecycleListener({
  WidgetsBinding? binding,
  this.onResume,
  this.onInactive,
  this.onHide,
  this.onShow,
  this.onPause,
  this.onRestart,
  this.onDetach,
  this.onExitRequested,
  this.onStateChange,
})

我们可以在State或者ViewModel上加入监听,需要注意的是,当组件退出时必须调用AppLifecycleState.dispose,否则会导致泄漏发生。

class _MyHomePageState extends State<MyHomePage> {

  AppLifecycleListener? _lifecycleListener;
  
  @override
  void initState() {
    super.initState();
    _lifecycleListener = AppLifecycleListener(
      onResume: () {
        print('onResume');
      },
      onInactive: () {
        print('onInactive');
      },
      onHide: () {
        print('onHide');
      },
      onShow: () {
        print('onShow');
      },
      onPause: () {
        print('onPause');
      },
      onRestart: () {
        print('onRestart');
      },
      onDetach: () {
        print('onDetach');
      },
      onExitRequested: () {
        ScaffoldMessenger.maybeOf(context)?.showSnackBar(const SnackBar(content: Text("拦截应用退出")));
        return Future.value(AppExitResponse.cancel);
      },
    );
  }
  
  @override
    super.dispose();
    _lifecycleListener?.dispose();
  }
}

onExitRequested

AppLifecycleListener里有一个监听应用退出的回调 onExitRequested,这个方法返回枚举值AppExitResponse。返回AppExitResponse.cancel表示取消此次退出操作,应用保持在前台;返回AppExitResponse.exit则表示不拦截,应用正常退出。

目前,onExitRequested只支持macOSLinux,并且在这两个平台上也不是全部的应用退出操作都是可以取消的,比如系统断点,异常退出这类退出是无法拦截取消的,所以不要依赖这个接口做一些数据保存的操作。

那么什么时候下的退出是可以取消的呢?Flutter 3.13还引入了一个退出接口 ServicesBinding.instance.exitApplication(AppExitType exitType),调用这个方法传入AppExitType.cancelable退出应用时,此次退出可取消,系统会回调到onExitRequested方法。

class _MyHomePageState extends State<MyHomePage> {

  AppLifecycleListener? _lifecycleListener;
  bool _shouldExit = false;
  String lastResponse = 'No exit requested yet';
  
  @override
  void initState() {
    super.initState();
    _lifecycleListener = AppLifecycleListener(
      onExitRequested: () async {
          final AppExitResponse response = _shouldExit ? AppExitResponse.exit : AppExitResponse.cancel;
          setState(() {
            lastResponse = 'App responded ${response.name} to exit request';
          });
          return response;
      },
    );
  }
  
  @override
    super.dispose();
    _lifecycleListener?.dispose();
  }
  
  Future<void> _quit() async {
    final AppExitType exitType = _shouldExit ? AppExitType.required : AppExitType.cancelable;
    setState(() {
      lastResponse = 'App requesting ${exitType.name} exit';
    });
    await ServicesBinding.instance.exitApplication(exitType);
  }

  void _radioChanged(bool? value) {
    value ??= true;
    if (_shouldExit == value) {
      return;
    }
    setState(() {
      _shouldExit = value!;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: SizedBox(
        width: 300,
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            RadioListTile<bool>(
              title: const Text('Do Not Allow Exit'),
              groupValue: _shouldExit,
              value: false,
              onChanged: _radioChanged,
            ),
            RadioListTile<bool>(
              title: const Text('Allow Exit'),
              groupValue: _shouldExit,
              value: true,
              onChanged: _radioChanged,
            ),
            const SizedBox(height: 30),
            ElevatedButton(
              onPressed: _quit,
              child: const Text('Quit'),
            ),
            const SizedBox(height: 30),
            Text(lastResponse),
          ],
        ),
      ),
    );
  }
}

Flutter 3.13 生命周期新组件 AppLifecycleListener

当选择Do Not Allow Exit时,_shouldExit = false。点击Exit按钮触发ServicesBinding.instance.exitApplication(AppExitType.cancelable),此时应用退出但可以取消。系统会回调到_lifecycleListener.onExitRequested,这个方法返回了AppExitResponse.cancel,应用退出的操作被取消了。