从AppLifecycleState.resumed事件导航到新的屏幕?

3 浏览
0 Comments

从AppLifecycleState.resumed事件导航到新的屏幕?

我试图在AppLifecycleState事件中启动一个新的屏幕,但是什么都没有发生。这是因为在这个事件中没有可用的上下文来包含导航器。

每次应用程序从恢复状态返回(AppLifecycleState.resumed),应用程序都必须打开锁屏。最简单的情况是,每次打开银行应用程序时都需要进行锁屏保护。

如何在代码的任何位置显示新屏幕?

我提供的不起作用的代码:

import 'package:alarm_prevozi/screens/home_screen/home_screen.dart';

import 'package:alarm_prevozi/screens/lock_screen/lock_screen.dart';

import 'package:flutter_localizations/flutter_localizations.dart';

import 'package:alarm_prevozi/helpers/translations.dart';

import 'package:flutter/material.dart';

void main() async {

// 然后启动应用程序

runApp(MyApp());

}

class MyApp extends StatefulWidget {

@override

_MyAppState createState() => _MyAppState();

}

class _MyAppState extends State with WidgetsBindingObserver {

BuildContext myContext;

@override

void initState() {

super.initState();

WidgetsBinding.instance.addObserver(this);

}

@override

void dispose() {

WidgetsBinding.instance.removeObserver(this);

super.dispose();

}

// 监听应用程序进入后台或前台状态

@override

void didChangeAppLifecycleState(AppLifecycleState state) {

if (state == AppLifecycleState.resumed) {

// 用户返回到我们的应用程序

_showLockScreenDialog();

} else if (state == AppLifecycleState.inactive) {

// 应用程序不活动

} else if (state == AppLifecycleState.paused) {

// 用户暂时退出我们的应用程序

} else if (state == AppLifecycleState.suspending) {

// 应用程序暂停(iOS中不使用)

}

}

// 主要初始化

@override

Widget build(BuildContext context) {

return MaterialApp(

localizationsDelegates: [

GlobalMaterialLocalizations.delegate,

GlobalWidgetsLocalizations.delegate,

],

// 告诉系统支持的语言

supportedLocales: translationService.supportedLocales(),

home: HomeScreen()

);

}

void _showLockScreenDialog() {

Navigator.of(context)

.pushReplacement(new MaterialPageRoute(builder: (BuildContext context) {

return LockScreen();

}));

}

}

0
0 Comments

问题的出现原因是在AppLifecycleState.resumed事件中从一个层级高于MaterialApp的观察者中访问Navigator,导致在推送路由时出现错误。

解决方法是使用一个全局键(GlobalKey)来访问MaterialApp提供的Navigator。首先,创建一个GlobalKey,并将其分配给MaterialApp的navigatorKey属性。然后,在触发AppLifecycleState.resumed事件时,通过访问navigatorKey.currentState来推送新的路由。

具体解决方法如下:

1. 在_MyAppState类中创建一个StreamController来处理resume事件,创建一个StreamSubscription来监听_stream的事件。

2. 在didChangeAppLifecycleState方法中,当state为AppLifecycleState.resumed时,通过_showLockScreenStream.add(true)向stream中添加一个事件。

3. 在build方法中,将navigatorKey分配给MaterialApp的navigatorKey属性。

4. 创建一个_showLockScreenDialog方法,在该方法中通过_navigatorKey.currentState来推送新的路由。

这样,当应用程序进入到前台时,会触发resume事件,并通过navigatorKey.currentState推送新的路由。这样就解决了从AppLifecycleState.resumed事件导航到新屏幕的问题。

需要注意的是,在使用GlobalKey时要谨慎使用,不要在整个应用程序中过多地使用它们。

以下是修改后的代码示例:

class _MyAppState extends State with WidgetsBindingObserver {

StreamController _showLockScreenStream = StreamController();

StreamSubscription _showLockScreenSubs;

GlobalKey _navigatorKey = GlobalKey();

void initState() {

super.initState();

WidgetsBinding.instance.addObserver(this);

_showLockScreenSubs = _showLockScreenStream.stream.listen((bool show) {

if (mounted && show) {

_showLockScreenDialog();

}

});

}

void dispose() {

WidgetsBinding.instance.removeObserver(this);

_showLockScreenSubs?.cancel();

super.dispose();

}

void didChangeAppLifecycleState(AppLifecycleState state) {

if (state == AppLifecycleState.resumed) {

_showLockScreenStream.add(true);

} else if (state == AppLifecycleState.inactive) {

// app is inactive

} else if (state == AppLifecycleState.paused) {

// user is about quit our app temporarily

} else if (state == AppLifecycleState.detached) {

// detached from any host views

}

}

Widget build(BuildContext context) {

return MaterialApp(

navigatorKey: _navigatorKey,

...

);

}

void _showLockScreenDialog() {

_navigatorKey.currentState.pushReplacement(

MaterialPageRoute(builder: (BuildContext context) {

return PassCodeScreen();

})

);

}

}

感谢您的帮助!但是,这仍然会产生Unhandled Exception: Navigator operation requested with a context that does not include a Navigator的错误。您是对的,我已更新答案。我认为这是使用GlobalKeys的一个很好的案例,但不建议在应用程序中过多地使用它们。使用GlobalKey解决方案后,您几乎可以跳过StreamController的部分。我将这个选择留给您。

0