首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >浏览器的后退按钮不触发parseRouteInformation,并抛出在小部件tree.error颤振中检测到的重复GlobalKey

浏览器的后退按钮不触发parseRouteInformation,并抛出在小部件tree.error颤振中检测到的重复GlobalKey
EN

Stack Overflow用户
提问于 2021-11-27 15:11:06
回答 1查看 281关注 0票数 0

我切换到Navigator 2.0,我可以设法改变页面在我的NavigationBar小部件中的导航按钮,但当点击浏览器的后退或前进按钮,该页面将不会更新面团显示的网址。如果我第二次按下它,它确实会返回,但会抛出Duplicate GlobalKey detected in widget tree.错误。

代码语言:javascript
复制
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>#781da]
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:
- Builder
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: 
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 251:49  throw_
packages/flutter/src/widgets/framework.dart 2939:15                           <fn>
packages/flutter/src/widgets/framework.dart 2963:16                           finalizeTree
packages/flutter/src/widgets/binding.dart 884:7                               drawFrame
packages/flutter/src/rendering/binding.dart 319:5                             [_handlePersistentFrameCallback]
packages/flutter/src/scheduler/binding.dart 1143:15                           [_invokeFrameCallback]
packages/flutter/src/scheduler/binding.dart 1080:9                            handleDrawFrame
packages/flutter/src/scheduler/binding.dart 996:5                             [_handleDrawFrame]
lib/_engine/engine/platform_dispatcher.dart 1003:13                           invoke
lib/_engine/engine/platform_dispatcher.dart 157:5                             invokeOnDrawFrame
lib/_engine/engine.dart 440:45                                                <fn>

我所有的小部件,不管它们是否是无状态os有状态的,都有const WidgetName({Key key}) : super(key: key)构造函数,在实例化它们时,我从不将父键传递给子部件。

我试图从小部件的构造函数中删除Key,但仍然得到了错误。

我从RouterDelegate中的Navigator中删除了键,重复的错误也消失了,但是仍然需要按两个后退按钮才能返回到上一页,然后编辑url手动抛出错误:

代码语言:javascript
复制
Could not navigate to initial route.
The requested route name was: "/retailers"
There was no corresponding route in the app, and therefore the initial route specified will be ignored and "/" will be used instead.

在我被覆盖的parseRouteInformation中,我设置了打印,它显示应用程序何时启动,而不是当我按下浏览器的后退或转发按钮时。

您能指出为什么RouteInformationParser不解析前一条路由并抛出Duplicate GlobalKey detected in widget tree.错误吗?

我查过了,RouterDelegate中的那个是我唯一声明的。关于我的应用你还有什么需要看的吗?

这是我的RouterDelegate:

代码语言:javascript
复制
class AppRouterDelegate extends RouterDelegate<RoutePath>
    with ChangeNotifier, PopNavigatorRouterDelegateMixin<RoutePath> {

  final GlobalKey<NavigatorState> navigatorKey;
  AppState appState = AppState();
  AppRouterDelegate() : navigatorKey = GlobalKey<NavigatorState>() {
    appState.addListener(notifyListeners);
    print('appState.addListener(notifyListeners) called');
  }
  @override
  RoutePath get currentConfiguration {
    print(
        'RouterDelegate.currentConfiguration appState.selectedPage is ${appState.selectedPage}');

    switch (appState.selectedPage) {
      case '/':
        return HomePath();
      case CyclistsLandingRoute:
        return CyclistsPath();
      case RetailersLandingRoute:
        return RetailersPath();
      case MapRoute:
        return MapPath();
      case AboutRoute:
        return AboutPath();
      case TermsOfServiceRoute:
        return TermsOfServicePath();
      case PrivacyPolicyRoute:
        return PrivacyPolicyPath();
      case PrivacySettingsRoute:
        return PrivacySettingsPath();
      case CommunityGuidelinesRoute:
        return CommunityGuidelinesPath();
      case LegalNoticeRoute:
        return LegalPath();
      default:
        return HomePath();
    }
  }

  @override
  Widget build(BuildContext context) {
    print("Delegate build");
    return Navigator(
        key: navigatorKey,
        pages: [
          MaterialPage(
              child: WebsitePageDisplay(
            appState: appState,
          ))
        ],
        onPopPage: (route, result) {
          print("onPopPage");
          if (!route.didPop(result)) {
            return false;
          }
          if (appState.selectedPage != null) {
            appState.selectedPage = null;
          }

          notifyListeners();
          return true;
        }
        );
  }

  @override
  Future<void> setNewRoutePath(RoutePath path) async {
    print('RouterDelegate.setNewRoutePath path is ${path.selectedPath}');
    appState.selectedPage = path.selectedPath;
  }
}

这是我的RouteInformationParser:

代码语言:javascript
复制
class AppRouteInformationParser extends RouteInformationParser<RoutePath> {
  @override
  Future<RoutePath> parseRouteInformation(
      RouteInformation routeInformation) async {
    print(
        'AppRouteInformationParser.parseRouteInformation called for ${routeInformation.location}');
    final Uri uri = Uri.parse(routeInformation.location);
    if (uri.pathSegments.length > 0) {
      print(
          'Uri.segments.first is: ${uri.pathSegments.first}, uri.path is: ${uri.path}');
    } else {
      print('AppRouteInformationParser uri has no segments and is $uri');
    }

    switch (routeInformation.location) {
      // switch (uri.pathSegments.first) {
      case '/':
        print('AppRouteInformationParser.urlSegment switch case : /');
        // return CyclistsPath();
        return HomePath();
      case CyclistsLandingRoute:
        print(
            'AppRouteInformationParser.routeInformation.location switch case: /cyclists');
        return CyclistsPath();
      case '/retailers':
        print(
            'AppRouteInformationParser.routeInformation.location switch case: /retailers');
        return RetailersPath();
      case '/map':
        print(
            'AppRouteInformationParser.routeInformation.location switch case: /map');
        return MapPath();
      case AboutRoute:
        print(
            'AppRouteInformationParser.routeInformation.location switch case: /about');
        return AboutPath();
      case TermsOfServiceRoute:
        print(
            'AppRouteInformationParser.routeInformation.location switch case: /terms-of-service');
        return TermsOfServicePath();
      case PrivacyPolicyRoute:
        print(
            'AppRouteInformationParser.routeInformation.location switch case: /privacy-policy');
        return PrivacyPolicyPath();
      case PrivacySettingsRoute:
        print(
            'AppRouteInformationParser.routeInformation.location switch case: /privacy-settings');
        return PrivacySettingsPath();
      case CommunityGuidelinesRoute:
        print(
            'AppRouteInformationParser.routeInformation.location switch case: /community-guidelines');
        return CommunityGuidelinesPath();
      case LegalNoticeRoute:
        print(
            'AppRouteInformationParser.routeInformation.location switch case: /legal-notice');
        return LegalPath();

      default:
        print(
            '### default AppRouteInformationParser.routeInformation.location switch case ## default: /');
        return HomePath();
    }

  }

  @override
  RouteInformation restoreRouteInformation(RoutePath path) {

    print(
        'AppRouteInformationParser.restoreRouteInformation called for path ${path.selectedPath}');

    switch (path.selectedPath) {
      case '/':
        // case CyclistsLandingRoute:
        print('restoreRouteInformation RouteInformation.location: /');
        return RouteInformation(location: '/');
      case '/cyclists':
        // case CyclistsLandingRoute:
        print('restoreRouteInformation RouteInformation.location: /cyclists');
        return RouteInformation(location: '/cyclists');

      case '/retailers':
        print('restoreRouteInformation RouteInformation.location: /retailers');
        return RouteInformation(location: '/retailers');
      case '/map':
        print('restoreRouteInformation RouteInformation.location: /map');
        return RouteInformation(location: '/map');
      case '/about':
        print('restoreRouteInformation RouteInformation.location: /about');
        return RouteInformation(location: '/about');
      case '/terms-of-service':
        print(
            'restoreRouteInformation RouteInformation.location: /terms-of-service');
        return RouteInformation(location: '/terms-of-service');
      case '/privacy-policy':
        print(
            'restoreRouteInformation RouteInformation.location: /privacy-policy');
        return RouteInformation(location: '/privacy-policy');
      case '/privacy-settings':
        print(
            'restoreRouteInformation RouteInformation.location: /privacy-settings');
        return RouteInformation(location: '/privacy-settings');
      case '/community-guidelines':
        print(
            'restoreRouteInformation RouteInformation.location: /community-guidelines');
        return RouteInformation(location: '/community-guidelines');
      case '/legal-notice':
        print(
            'restoreRouteInformation RouteInformation.location: /legal-notice');
        return RouteInformation(location: '/legal-notice');
      default:
        print(
            'restoreRouteInformation  ### Default RouteInformation.location: /cyclists');
        return RouteInformation(location: '/cyclists');
    }
  }
}

这是AppState:

代码语言:javascript
复制
class AppState extends ChangeNotifier {
  String _selectedPage;
  AppState() : _selectedPage = null;

  String get selectedPage => _selectedPage;

  Widget get selectedWidget {
    switch (selectedPage) {
      case CyclistsLandingRoute:
        return CyclistLanding();
        break;
      case RetailersLandingRoute:
        return RetailerLanding();
        break;
      case MapRoute:
        return CityMap();
        break;
      case AboutRoute:
        return AboutUs();
        break;
      case TermsOfServiceRoute:
        return TermsOfService();
        break;
      case PrivacyPolicyRoute:
        return PrivacyPolicy();
        break;
      // case PrivacySettingsRoute:
      //   return PrivacyPolicySettings();
      //   break;
      case CommunityGuidelinesRoute:
        return CommunityGuidelines();
        break;
      case LegalNoticeRoute:
        return LegalNotice();
        break;
      default:
        return CyclistLanding();
        notifyListeners();
    }
    notifyListeners();
  }

  set selectedPage(String page) {
    print('AppState setting selectedPage to $page');
    _selectedPage = page;
    notifyListeners();
  }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-11-29 09:29:12

我终于发现了这个问题:

在main.dart构建方法中,我返回一个以MaterialApp.router为主的MaterialApp,而不是直接返回MaterialApp.router,并将所有参数移到其中。现在一切都如期而至。

错误的方向:

代码语言:javascript
复制
  AppRouterDelegate _routerDelegate = AppRouterDelegate();

  AppRouteInformationParser _routeInformationParser =
      AppRouteInformationParser();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '',
      color: Colors.red,
      localizationsDelegates: [
        const AppLocalizationsDelegate(),
        GlobalMaterialLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
      ],
      supportedLocales: [
        const Locale('en', 'US'),
        const Locale('it', 'IT')
//        const Locale('es', 'ES'),
      ],
      localeResolutionCallback:
          (Locale locale, Iterable<Locale> supportedLocales) {
        for (Locale supportedLocale in supportedLocales) {
          if (supportedLocale.languageCode == locale.languageCode ||
              supportedLocale.countryCode == locale.countryCode) {
            print('Web device Locale is $locale');
            return supportedLocale;
          }
        }
        return supportedLocales.first;
      },
      debugShowCheckedModeBanner: false,
      home: MaterialApp.router(
          routeInformationParser: _routeInformationParser,
          routerDelegate: _routerDelegate),
    );
  }

正确的方法是:

代码语言:javascript
复制
AppRouterDelegate _routerDelegate = AppRouterDelegate();

  AppRouteInformationParser _routeInformationParser =
      AppRouteInformationParser();

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routeInformationParser: _routeInformationParser,
      routerDelegate: _routerDelegate,
      debugShowCheckedModeBanner: false,
      title: '',
      color: Colors.red,
      localizationsDelegates: [
        const AppLocalizationsDelegate(),
        GlobalMaterialLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
      ],
      supportedLocales: [
        const Locale('en', 'US'),
        const Locale('it', 'IT')
//        const Locale('es', 'ES'),
      ],
      localeResolutionCallback:
          (Locale locale, Iterable<Locale> supportedLocales) {
        for (Locale supportedLocale in supportedLocales) {
          // if (UniversalPlatform.isWeb) {
          if (supportedLocale.languageCode == locale.languageCode ||
              supportedLocale.countryCode == locale.countryCode) {
            print('Web device Locale is $locale');
            return supportedLocale;
          }
        }
        return supportedLocales.first;
      },
      // localeListResolutionCallback: ,
    );
  }
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70136010

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档