在Flutter中,Getx包unknownRoute不工作



我开始学习Getx在扑动,并使用导航。

我想设置unknownRoute,以防在namedroute中出现拼写错误等,所以应用程序应该转到默认页面。

我这样做:

return GetMaterialApp(
title: 'Named navigation',
unknownRoute: GetPage(name: '/notfound', page: () => UnknownRoutePage()),
initialRoute: '/', // this defines with route will be opened first
getPages: [
GetPage(name: '/', page: () => MyNavigationNamed()),
GetPage(name: '/second', page: () => SecondScreenNamed()),
GetPage(name: '/third', page: () => ThirdParametersScreenNamed()),
GetPage(
name: '/third_with_built_param/:someValue',
page: () => ThirdParametersScreenNamed()),
],

我有一个小部件:

class UnknownRoutePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(child: Text('UNKNOWN ROUTE')));
}
}

然而,当我试图通过在路由名称中犯错误来测试它时,就像这样:

ElevatedButton(
onPressed: () {
Get.toNamed(
'/s');     //THIS IS A DUMMY INCORRECT NAME TO TESTING
},
child: Text('Error in route name, goes to defalt set above.'),
),

我希望我的UnknownRoutePage()打开。

然而,我得到这个消息:

The following assertion was thrown building Directionality(textDirection: ltr):
'package:flutter/src/widgets/framework.dart': Failed assertion: line 5033 pos 14: '_dependents.isEmpty': is not true.

Either the assertion indicates an error in the framework itself, or we should provide substantially more information in this error message to help you determine and fix the underlying cause.
In either case, please report this assertion by filing a bug on GitHub:
https://github.com/flutter/flutter/issues/new?template=2_bug.md
The relevant error-causing widget was: 
Directionality file:///Users/reuvenberman/Developer/flutter/.pub-cache/hosted/pub.dartlang.org/get-4.3.8/lib/get_navigation/src/root/get_material_app.dart:217:12
When the exception was thrown, this was the stack: 
#2      InheritedElement.debugDeactivated.<anonymous closure> (package:flutter/src/widgets/framework.dart:5033:14)
#3      InheritedElement.debugDeactivated (package:flutter/src/widgets/framework.dart:5035:6)
#4      _InactiveElements._deactivateRecursively.<anonymous closure> (package:flutter/src/widgets/framework.dart:1869:15)
#5      _InactiveElements._deactivateRecursively (package:flutter/src/widgets/framework.dart:1871:6)
#6      ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:4628:14)
...
====================================================================================================
======== Exception caught by widgets library =======================================================
The following assertion was thrown while finalizing the widget tree:
Duplicate GlobalKey detected in widget tree.
The following GlobalKey was specified multiple times in the widget tree. This will lead to parts of the widget tree being truncated unexpectedly, because the second time a key is seen, the previous instance is moved to the new location. The key was:
- [LabeledGlobalKey<NavigatorState>#56deb Key Created by default]
This was determined by noticing that after the widget with the above global key was moved out of its previous parent, that previous parent never updated during this frame, meaning that it either did not update at all or updated before the widget was moved, in either case implying that it still thinks that it should have a child with that global key.
The specific parent that did not update after having one or more children forcibly removed due to GlobalKey reparenting is:
- Directionality(textDirection: ltr)
A GlobalKey can only be specified on one widget at a time in the widget tree.
When the exception was thrown, this was the stack: 
#0      BuildOwner.finalizeTree.<anonymous closure> (package:flutter/src/widgets/framework.dart:2900:15)
#1      BuildOwner.finalizeTree (package:flutter/src/widgets/framework.dart:2925:8)
#2      WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:877:19)
#3      RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:328:5)
#4      SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1144:15)
...

为什么不工作?

感谢

我遇到了同样的问题,但是我深入研究了Get代码,发现有一个matchRoute()方法将返回"/"unknownRoute。

——比;简而言之,要使unknownRoute工作,您的初始路由不能是"/",它可以是其他任何东西,例如"/home", "/main", "/init",但它不能是"/"


我为它创建了一个PR: https://github.com/jonataslaw/getx/pull/2256

我也面临同样的问题,也找不到有关主题的任何信息。在进行了一些测试并检查了实际的包代码之后,我得出的结论是,GetX只关心它是否能够匹配URI开头的路由。所以如果你有一条路线然后在"/"例如"/non-existent-route/1/2/3/"仍然会匹配"/"因为它以"/"开头。类似地,如果你有一个像"/admin-area"另一个是&;/admin-area/home&;然后"/管理员区/non-existent-route/1/2/3/";仍然会匹配到"/admin-area"和一个像"/admin-area/home/non-exist -route/1/2/3/"这样的URI;仍然会匹配"/admin-area/home"由于这不是web的预期行为,当使用currentRoute在导航中突出显示当前页面时,它可能会导致问题,并且考虑到GetX的文档如此糟糕,我只能假设这是一个bug。

我能正确解决这个问题的唯一方法是不使用GetMaterialApp的getPages属性,而是使用onGenerateRoute。得到的。toNamed仍然有效,路由器只会路由到完全匹配的,像这样:

@override
Widget build(BuildContext context) {
return GetMaterialApp(
initialRoute: "/",
onGenerateRoute: (RouteSettings route) {
var uri = Uri.parse(route.name!);
switch (uri.path) {
case "/":
return MaterialPageRoute(
settings: route,
builder: (context) => const RootPage(),
);
default:
return MaterialPageRoute(
settings: route,
builder: (context) => const UnkownPage(),
);
}
},
);
}

如果你愿意,你也可以把这个逻辑移出GetMaterialApp,像这样:

@override
Widget build(BuildContext context) {
return GetMaterialApp(
initialRoute: "/",
onGenerateRoute: generateRoutes
},
);
}
//another file
Route<dynamic> generateRoutes(RouteSettings route) {
var uri = Uri.parse(route.name!);
switch (uri.path) {
case "/":
return MaterialPageRoute(
settings: route,
builder: (context) => const UnimplementedPage('Unkown'),
);
default:
return MaterialPageRoute(
settings: route,
builder: (context) => const UnimplementedPage('Unkown'),
);
}
}

我遇到了一个类似的问题,但是我没有收到任何错误消息。相反,当我试图导航到一个不存在的页面时,我总是在起始页结束。我没有找到任何关于这一点的澄清。

我的解决方案是为initialRoute设置一些更重的内容,例如:initialRoute: '/beginpage'。'/'和'/start'对我不起作用,也许它们是一些保留的路由。我在你的代码中看到了同样的问题,试着改变它。

如果这没有帮助,你可以看看我在github上找到的一个现成的例子,它帮助我确定了我的问题:https://github.com/ducafecat/getx_quick_start.

我发现了一个简单的方法,你可以跳过主页在"getPage:"因为"initialRoute:"实施。

return GetMaterialApp(
title: 'Named navigation',
unknownRoute: GetPage(name: '/notfound', page: () => UnknownRoutePage()),
initialRoute: '/',
getPages: [
GetPage(name: '/second', page: () => SecondScreenNamed()),
GetPage(name: '/third', page: () => ThirdParametersScreenNamed()),
GetPage(
name: '/third_with_built_param/:someValue',
page: () => ThirdParametersScreenNamed()),
],

试试。

我解决了

交往UnknownRoute

第一个AppInformationParser放入GetMaterialApp.router

routeInformationParser: AppInformationParser()

return GetMaterialApp.router(
title: 'ACRI',
debugShowCheckedModeBanner: false,
theme: AppTheme.appTheme,
themeMode: ThemeMode.light,
locale: Get.locale ?? const Locale('tr'),
translations: AppLocalization(),
routerDelegate: Get.createDelegate(
backButtonPopMode: PopMode.Page,
notFoundRoute: AppPages.pageNotFound,
),
localizationsDelegates: AppLocalizationDelegate.appDelegates,
supportedLocales: AppLocalizationDelegate.supportedLocales,
routeInformationParser: AppInformationParser(),
backButtonDispatcher: AppBackButtonDispatcher(),
getPages: AppPages.pages,
initialBinding: AccountBinding(),
unknownRoute: AppPages.pageNotFound,
);
创建AppInformationParser
class AppInformationParser extends RouteInformationParser<GetNavConfig> {
/// [initialRoute] => [/]
AppInformationParser({
String? initialRoute,
})  : initialRoute = initialRoute ?? '/',
super();
/// Initial route
/// default '/'
final String initialRoute;
@override
Future<GetNavConfig> parseRouteInformation(
RouteInformation routeInformation,
) {
String? location = routeInformation.location; // => [/]
if (location == '/') {
if (!Get.routeTree.routes.any((e) => e.name == '/')) {
location = initialRoute;
}
}
// if (!Get.routeTree.routes.any((e) => false)) {
//   location = AppRoutes.notFound;
// }
final matchResult = Get.routeTree.matchRoute(location ?? initialRoute);
String? matchResultLocation = matchResult.route?.name;
log("App Information Parser location : $location");
log("Match Result Parser location : ${matchResult.route?.name}");
if (matchResultLocation != location) {
location = AppRoutes.notFound;
} else if (matchResultLocation == AppRoutes.navigation) {
location = AppRoutes.home;
} else if (matchResultLocation == AppRoutes.list) {
location = AppRoutes.vehicles;
} else if (matchResultLocation == AppRoutes.report) {
location = AppRoutes.vehicleReport;
} else if (matchResultLocation == AppRoutes.map) {
location = AppRoutes.mapVehicles;
}
final result = Get.routeTree.matchRoute(location ?? initialRoute);
return SynchronousFuture(
GetNavConfig(
currentTreeBranch: result.treeBranch,
location: location,
state: routeInformation.state,
),
);
}
@override
RouteInformation? restoreRouteInformation(GetNavConfig configuration) {
return RouteInformation(
location: configuration.location,
state: configuration.state,
);
}
}

给你输入的路由器名

final matchResult = Get.routeTree.matchRoute(location ?? initialRoute);
String? matchResultLocation = matchResult.route?.name;

和比较location路由器

if (matchResultLocation != location) {
location = AppRoutes.notFound;
}

如果matchResultLocation不比较location,那么它是未知路由器

最后对GetNavConfig再次添加matchRoute方法求解UnknownRoute

final result = Get.routeTree.matchRoute(location ?? initialRoute);
return SynchronousFuture(
GetNavConfig(
currentTreeBranch: result.treeBranch,
location: location,
state: routeInformation.state,
),
);

已解决:首先,我使用了GetMaterialApp中的getPages属性:

return GetMaterialApp(
localizationsDelegates: context.localizationDelegates,
supportedLocales: context.supportedLocales,
locale: context.locale,
debugShowCheckedModeBanner: false,
title: Constants.appName,
//Rutas fluro
// onGenerateRoute: Flurorouter.router.generator,
// onGenerateRoute: (RouteSettings route){
//   var uri = Uri.parse(route.name!);
//   switch (uri.path) {
//     case "/":
//       return GetMaterialPageView(
//         settings: route,
//         builder: (context) => const RootPage(),
//       );
//     default:
//       return MaterialPageRoute(
//         settings: route,
//         builder: (context) => const UnkownPage(),
//       );
//   }  
// },
initialBinding: InitialBindings(),
initialRoute: AppRoutes.initialRoute,
getPages: AppPages.pages,
unknownRoute: GetPage(name: '/notfound', page: () => const Screen404()),
// routes: AppRoutes.getAppRoutes(),
theme: AppTheme.lightTheme,
);

Inside of AppPages。我有我的项目的所有页面,每个页面看起来像这样:

GetPage(
name: AppRoutes.SPLASH,
page: () => AppRoutes.routes.contains(Get.currentRoute)
?SplashScreen()
:const Screen404(),
),

在返回页面之前,我使用page属性来返回当前路由,并验证该路由是否与我在AppRoutes中定义的路由相同,如果不相同,我返回一个404屏幕。

如果路由有如下参数:

GetPage(  
name: "${AppRoutes.CANCEL_RESERVATION}/:id_reservation",
page: (){
//TODO VERIFICAR QUE ID EXISTA EN LISTADO DE AMENIDADES
print(Get.parameters);
print(Get.currentRoute);
final id = int.tryParse(Get.parameters['id_reservation']!);
final controller = Get.find<MyReservationsController>();
controller.getReservationSelectedToCancel(id);
if(controller.myReservationToCanel != null){
return CancelReservationScreen(
reservation: id,
); 
}else{
return const Screen404();
}
},
binding: MyReservationsBinding(),
),

这样我们也可以使用绑定。

最新更新