开发安卓的朋友都知道在activity的切换时是有 onPause ,onResume 监听的,而flutter没有提供类似的功能,下面我们在flutter中实现一个类似android中的 onPause ,onResume。
1.既然我们是在state中监听页面的状态,那么我们首先在state中混入我们的生命周期方法,其中 StateLifecycleManager 是我们自定义的,用来管理和存储 state 的单例类。我们在state中initState(),dispose()添加或移除监听。
mixin LifecycleMixin<T extends StatefulWidget> on State<T> {
@mustCallSuper
@override
void initState() {
super.initState();
StateLifecycleManager.instance.addLifecycle(this);
}
@mustCallSuper
@override
void dispose() {
StateLifecycleManager.instance.removeLifecycle(this);
super.dispose();
}
///页面回到正在展示状态
@protected
void onResume();
///页面处于非正在展示中
@protected
void onPause();
}
2.实现 StateLifecycleManager 类,内部存储了一个Map,Map中的键:state持有的widget的类名,值:第一步实现的LifecycleMixin。这样我们就可以在页面监听器中通过widget小部件的名称进行对应的操作。
class StateLifecycleManager {
factory StateLifecycleManager() {
return _getInstance();
}
static final StateLifecycleManager _instance = StateLifecycleManager._();
static StateLifecycleManager get instance => _instance;
static StateLifecycleManager _getInstance() {
return _instance;
}
final Map<String,LifecycleMixin> _map = {};
StateLifecycleManager._();
///添加
addLifecycle(LifecycleMixin lifecycleMixin) {
if (!_map.containsValue(lifecycleMixin)) {
_map[lifecycleMixin.widget.runtimeType.toString()] = lifecycleMixin;
}
}
///移除
removeLifecycle(LifecycleMixin lifecycleMixin) {
if (_map.containsValue(lifecycleMixin)) {
_map.remove(lifecycleMixin.widget.runtimeType.toString());
}
}
onResume(String routerName) {
if(_map.containsKey(routerName)){
_map[routerName]?.onResume();
}
}
onPause(String routerName) {
if(_map.containsKey(routerName)){
_map[routerName]?.onPause();
}
}
}
3.实现 StateNavigatorObserver 类,重写didPop方法,此方法是在某个页面关闭后调用(页面关闭正是我们可以实现onResume的时机)。同理,重写didPush方法,此方法是在某个页面打开后调用(实现onPause的时机)
class StateNavigatorObserver extends NavigatorObserver {
StateNavigatorObserver();
@override
void didPop(Route route, Route? previousRoute) {
super.didPop(route, previousRoute);
if((route is CupertinoPageRoute || route is MaterialPageRoute)){
String? routerName = previousRoute?.settings.name;
if(routerName != null){
StateLifecycleManager.instance.onResume(routerName);
}
}
}
@override
void didPush(Route route, Route? previousRoute) {
super.didPush(route, previousRoute);
if((route is CupertinoPageRoute || route is MaterialPageRoute)){
String? routerName = previousRoute?.settings.name;
if(routerName != null){
StateLifecycleManager.instance.onPause(routerName);
}
}
}
}
- 添加 navigatorObservers
MaterialApp(
...
navigatorObservers: [
///自定义的 StateNavigatorObserver 类
StateNavigatorObserver(),
],
...
)
- 使用,在需要监听的页面上实现 LifecycleMixin 就可以了。 前面提到StateLifecycleManager中Map存储Key的是(widget的类名),那这名称是怎么设置的呢? 这里要注意 Navi.push(context, const NextPage()) 打开新页面的方法。
class Navi {
/// ios样式
static push(BuildContext context, Widget page,
{String? routeString}) {
routeString ??= page.runtimeType.toString();
Navigator.push(
context,
CupertinoPageRoute(
builder: (context) => page,
/// 设置RouteSettings后在 StateNavigatorObserver 就可以获取到对应的page名称
settings: RouteSettings(name: routeString),
),
);
}
}
class LifePage extends StatefulWidget {
const LifePage({Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() {
return LifePageState();
}
}
class LifePageState extends State<LifePage> with LifecycleMixin {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const AppbarTitle(title: "生命周期测试",),
body: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(
height: 5,
width: double.infinity,
),
TextButton(
onPressed: () {
Navi.push(context, const NextPage());
},
style: TextButton.styleFrom(
backgroundColor: Colors.blue,
minimumSize: const Size(0, 40)
),
child: const Text(
'打开下一个页面',
style: TextStyle(color: Colors.white),
)),
],
),
);
}
@override
void onPause() {
Printer.error('onPause --> ${runtimeType.toString()}', stackTrace: StackTrace.current);
}
@override
void onResume() {
Printer.error('onResume --> ${runtimeType.toString()}', stackTrace: StackTrace.current);
}
}
好了,经过前面的一顿操作之后App就可以监听onPause和onResume了!!!
不足之处,欢迎大家指正。