Flutter集成GoRouter后无报错但导航功能失效求助
Flutter GoRouter 导航无响应问题排查
问题现象
点击按钮调用以下代码尝试导航到profilecontent页面时无任何反应,无报错信息:
() { context.goNamed( RouteNameConstants.profilecontent, pathParameters: {"clicked": "about"}, ); }
控制台仅输出窗口焦点变化等无关日志:
D/VRI[MainActivity](32580): handleWindowFocusChanged mWindowFocusChanged true mUpcomingWindowFocus false mAdded true D/VRI[MainActivity](32580): onFocusEvent true D/VRI[MainActivity](32580): send msg MSG_WINDOW_FOCUS_CHANGED with caller android.view.ViewRootImplExtImpl.markAndDumpWindowFocusChangeMsg:956 android.view.ViewRootImpl.windowFocusChanged:9837 android.view.ViewRootImpl$WindowInputEventReceiver.onFocusEvent:9550 android.os.MessageQueue.nativePollOnce:-2 android.os.MessageQueue.next:349 android.os.Looper.loopOnce:186 android.os.Looper.loop:351 android.app.ActivityThread.main:8404 java.lang.reflect.Method.invoke:-2 com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run:584 com.android.internal.os.ZygoteInit.main:1013 <bottom of call stack> <bottom of call stack> <bottom of call stack> <bottom of call stack> <bottom of call stack> <bottom of call stack> <bottom of call stack> <bottom of call stack> <bottom of call stack> D/VRI[MainActivity](32580): handleWindowFocusChanged mWindowFocusChanged true mUpcomingWindowFocus true mAdded true D/TrafficStats(32580): tagSocket(3) with statsTag=0xffffffff, statsUid=-1 D/TrafficStats(32580): tagSocket(199) with statsTag=0xffffffff, statsUid=-1 D/OplusScrollToTopManager(32580): com.shoppier.discountlo/com.shoppier.discountlo.MainActivity,This DecorView@c3dec38[MainActivity] change focus to true
相关代码
路由定义
import 'package:discountlo/core/route_constant.dart'; import 'package:discountlo/features/auth/views/otp_view.dart'; import 'package:discountlo/features/auth/views/phone_view.dart'; import 'package:discountlo/features/home/view/filter_view.dart'; import 'package:discountlo/features/home/view/profile_content_view.dart'; import 'package:discountlo/features/home/view/profile_view.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:discountlo/features/auth/views/onboarding_screen.dart'; import 'package:discountlo/features/auth/views/splash_view.dart'; import 'package:discountlo/features/home/view/home_view.dart'; import 'auth_changes.dart'; import 'error_page.dart'; import 'package:flutter/material.dart'; import 'features/auth/controller/auth_controller.dart'; final _key = GlobalKey<NavigatorState>(); final routeProvider = Provider<GoRouter>( (ref) { return GoRouter( navigatorKey: _key, debugLogDiagnostics: true, routes: [ GoRoute( name: RouteNameConstants.home, path: "/", pageBuilder: (BuildContext context, GoRouterState state) => MaterialPage( child: const HomeView(), ), ), GoRoute( path: "/splash", name: RouteNameConstants.splash, pageBuilder: (BuildContext context, GoRouterState state) => MaterialPage( child: const SplashScreen(), ), ), GoRoute( path: "/otp", name: RouteNameConstants.otp, pageBuilder: (BuildContext context, GoRouterState state) => MaterialPage( child: OTPView( phoneNumber: state.pathParameters['phoneNumber']!, ), ), ), GoRoute( path: "/phone", name: RouteNameConstants.phone, pageBuilder: (BuildContext context, GoRouterState state) => MaterialPage( child: const PhoneView(), ), ), GoRoute( path: "/profile", name: RouteNameConstants.profile, pageBuilder: (BuildContext context, GoRouterState state) => MaterialPage( child: const ProfileView(), ), ), GoRoute( path: "/profilecontent", name: RouteNameConstants.profilecontent, pageBuilder: (BuildContext context, GoRouterState state) => MaterialPage( child: ProfileContentView( clicked: state.pathParameters['clicked']!, ), ), ), GoRoute( path: "/onboard", name: RouteNameConstants.onboarding, pageBuilder: (BuildContext context, GoRouterState state) => MaterialPage( child: const OnboardingView(), ), ), GoRoute( path: "/error/:text", name: RouteNameConstants.error, pageBuilder: (BuildContext context, GoRouterState state) => MaterialPage( child: ErrorPage(text: state.pathParameters['text']!, ), ), GoRoute( path: "/auth/:uid", name: RouteNameConstants.authState, pageBuilder: (BuildContext context, GoRouterState state) { return MaterialPage( child: AuthChanges(uid: state.pathParameters['uid']!, ); }, ), GoRoute( path: "/filter/:index/:category", name: RouteNameConstants.filter, pageBuilder: (BuildContext context, GoRouterState state) { debugPrint("sdvf ${state.pathParameters}"); return MaterialPage( child: FilterView( index: double.tryParse(state.pathParameters['index']!)!.toInt(), category: state.pathParameters['category']!, ), ); }, ), ], redirect: (context, state) { final loginState = ref.watch(authStateChangeProvider); if (loginState.isLoading) { return state.namedLocation(RouteNameConstants.splash); } else if (loginState.hasError) { return state.namedLocation( RouteNameConstants.error, pathParameters: { "text": loginState.error.toString(), }, ); } else if (loginState.value != null) { return state.namedLocation(RouteNameConstants.authState, pathParameters: {"uid": loginState.value!.uid}); } else { return state.namedLocation(RouteNameConstants.onboarding); } }, ); }, );
路由常量类
class RouteNameConstants { static const String home = 'home'; static const String splash = 'splash'; static const String onboarding = 'onboard'; static const String authState = 'auth'; static const String error = 'error'; static const String filter = 'filter'; static const String profile = 'profile'; static const String phone = 'phone'; static const String otp = 'otp'; static const String profilecontent = 'profilecontent'; }
Main.dart代码
void main() { WidgetsFlutterBinding.ensureInitialized(); SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]) .then((_) async { await Firebase.initializeApp(); await FirebaseAppCheck.instance .activate(androidProvider: AndroidProvider.playIntegrity); runApp( const ProviderScope( child: MyApp(), ), ); }); FlutterError.demangleStackTrace = (StackTrace stack) { if (stack is stack_trace.Trace) return stack.vmTrace; if (stack is stack_trace.Chain) return stack.toTrace().vmTrace; return stack; }; } class MyApp extends ConsumerWidget { const MyApp({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { return MaterialApp.router( debugShowCheckedModeBanner: false, title: 'DiscountLo', theme: AppTheme.theme, locale: ref.watch(languageNotifierProvider), localizationsDelegates: { AppLocalizations.delegate, GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate }, supportedLocales: [Locale("en"), Locale("hi")], routerDelegate: ref.watch(routeProvider).routerDelegate, routeInformationParser: ref.watch(routeProvider).routeInformationParser, routeInformationProvider: ref.watch(routeProvider).routeInformationProvider, ); } }
问题原因及解决方法
1. 路由参数不匹配
profilecontent路由的path定义为/profilecontent,但导航时传递了pathParameters: {"clicked": "about"},而该路由的path中未声明对应的参数占位符(如/profilecontent/:clicked),导致GoRouter无法匹配路由,导航失败。
修复: 修改profilecontent路由的path,添加参数占位符:
GoRoute( path: "/profilecontent/:clicked", // 添加参数占位符 name: RouteNameConstants.profilecontent, pageBuilder: (BuildContext context, GoRouterState state) => MaterialPage( child: ProfileContentView( clicked: state.pathParameters['clicked']!, ), ), ),
2. Redirect逻辑拦截导航
redirect函数会根据authStateChangeProvider的状态强制重定向路由,当你尝试导航时,可能被自动跳转到splash、authState或onboarding页面。
验证与修复:
- 临时注释
redirect函数,测试导航是否正常。若正常,说明是重定向逻辑导致的问题。 - 调整
redirect逻辑,允许在特定状态下访问profilecontent页面:
redirect: (context, state) { final loginState = ref.watch(authStateChangeProvider); // 允许直接导航到profilecontent页面 if (state.name == RouteNameConstants.profilecontent) { return null; } if (loginState.isLoading) { return state.namedLocation(RouteNameConstants.splash); } else if (loginState.hasError) { return state.namedLocation( RouteNameConstants.error, pathParameters: { "text": loginState.error.toString(), }, ); } else if (loginState.value != null) { return state.namedLocation(RouteNameConstants.authState, pathParameters: {"uid": loginState.value!.uid}); } else { return state.namedLocation(RouteNameConstants.onboarding); } },
3. 语法错误导致路由初始化失败
路由定义中存在两处语法错误:
ErrorPage构造函数缺少闭合括号:
改为:child: ErrorPage(text: state.pathParameters['text']!,child: ErrorPage(text: state.pathParameters['text']!),AuthChanges构造函数缺少闭合括号:
改为:child: AuthChanges(uid: state.pathParameters['uid']!,child: AuthChanges(uid: state.pathParameters['uid']!),
这些错误会导致GoRouter初始化异常,进而影响导航功能。
4. 查看GoRouter调试日志
已开启debugLogDiagnostics: true,可在控制台查看GoRouter输出的路由处理日志,确认导航请求是否被重定向、路由匹配是否成功。
内容的提问来源于stack exchange,提问作者abhi jain
相关产品推荐
相关产品推荐

