监听Flutter App切换前后台,支持单页面和全局

开发时候,我们会通过App是否在前台运行做一些操作,我们可以监听下面两种情况:

  1. 全局监听:不管在哪个页面,只要App里面切换了前后台就会触发,常用于数据埋点等
  2. 单页面监听:只有在某个页面进行App切换前后台才会触发,常用于页面数据刷新等

App状态以及流转

App生命周期状态有下面的几个:

1、resumed
App是可见状态并且接受用户的交互。

2、inactive
App不是激活状态并且不再接受用户的交互,下一步将会切换到paused状态,inactive状态持续时间很短。

在Android上,下面的行为会让App进入到inactive状态

  • 关闭屏幕
  • 有电话打进来
  • 展示系统对话框

在iOS上,下面的行为会让App进入到inactive状态

  • 关闭屏幕
  • 有电话打进来
  • 应用程序在响应Touch ID或者Face ID等
  • 进入到应用切换器或者控制中心

3、paused
应用程序切换到了后台,用户不可见不再接受用户交互,在当前状态时候,Flutter会做一些优化,例如停止执行PlatformDispatcher.onBeginFrame 和 PlatformDispatcher.onDrawFrame来节能。

4、detached
Flutter没有视图展示的时候的状态,一般会在App退出的时候执行。

各个操作导致的状态流转;

image.png

全局监听状态变更

针对于全局监听,我们可以使用SystemChannels去实现,将下面的代码放置在runApp之前即可:

SystemChannels.lifecycle.setMessageHandler((msg) async {  
  debugPrint('SystemChannels> $msg');  
  // msg是个字符串,是下面的值
  // AppLifecycleState.resumed
  // AppLifecycleState.inactive
  // AppLifecycleState.paused
  // AppLifecycleState.detached
  return msg;  
});

runApp(MyApp());

单页面监听状态变更

针对于单页面监听,我们需要用到StatefulWidget和WidgetsBindingObserver,为什么不能使用Stateless组件呢?因为Stateless组件没有完整的生命周期,无法注册事件监听;

WidgetsBindingObserver 会为组件添加一系列生命周期,官网文档给出了说明

image.png

对于App状态改变的生命周期,我们使用didChangeAppLifecycleState;

void didChangeAppLifecycleState(AppLifecycleState state) { }

具体实现如下所示

import 'package:flutter/material.dart';  
  
class TestLifecycle extends StatefulWidget {  
  const TestLifecycle({super.key});  
  
  @override  
  State<TestLifecycle> createState() => _TestLifecycleState();  
}  
  
class _TestLifecycleState extends State<TestLifecycle>  
    with WidgetsBindingObserver {  
  @override  
  void initState() {  
    super.initState();  
    WidgetsBinding.instance.addObserver(this);  
  }  
  
  @override  
  void didChangeAppLifecycleState(AppLifecycleState state) {  
    super.didChangeAppLifecycleState(state);  
    if (state == AppLifecycleState.resumed) {  
      print("切换到了前台");  
    } else if (state == AppLifecycleState.paused) {  
      print("切换到了后台");  
    }  
  }  
  
  @override  
  void dispose() {  
    WidgetsBinding.instance.removeObserver(this);  
    super.dispose();  
  }  
  
  @override  
  Widget build(BuildContext context) {  
    return Container();  
  }  
}

参考文档

留下回复