Flutter - 使用 NavigatorObserver 时出现 GlobalKey 错误

问题描述 投票:0回答:1


我有一个方法,每次在导航器堆栈中推送/弹出新路由时都需要调用。基本上,每次用户从一个屏幕转到另一个屏幕时。

我读到,执行此操作的最佳方法是使用 NavigatorObserver。 我尝试以这种方式实现它:

class NavigationObserver extends NavigatorObserver {
  @override
  void didPush(Route route, Route? previousRoute) {
    super.didPush(route, previousRoute);

    NotificationsViewState().updateNotifs(); // "Notifications" page
    NotifScrollContentState().updateNotifs(); // content of the notifications modal
  }
}

使用这个类,我在我的主 MaterialApp 中实现了它:

MaterialApp(
    navigatorObservers: [NavigationObserver()],
    // etc...

这导致了一个错误,暗示 GlobalKeys 可能是其中的原因:

GlobalKey 在一个小部件的子列表中多次使用。
有问题的 GlobalKey 是:[GlobalObjectKey_WidgetsAppState#263c0]
具有该键的小部件的父级是: _FocusInheritedScop
第一个使用该键实例化的孩子变成了: 导航器-[GlobalObjectKey_WidgetsAppState#263c0]
使用该键实例化的第二个子项是: _焦点继承范围
GlobalKey 一次只能在小部件树中的一个小部件上指定。

我不是 Dart 专家,所以我确实很难理解如何解决这个问题。 仅供参考,我在 Flutter 应用程序中使用的唯一 GlobalKeys 仅用于实现 AnimatedLists,所以我认为这不相关。

flutter dart mobile
1个回答
0
投票

我也遇到了同样的问题,虽然不知道具体原因, 我能够通过将 didPush、didPop、didReplace 和 didRemove 等函数中的繁重任务移至单独的线程来解决这个问题。

看来在 didPush 函数中运行以下代码可能是原因:

NotificationsViewState().updateNotifs(); // "Notifications" page
NotifScrollContentState().updateNotifs(); // content of the notifications modal

由于我对原因没有准确的了解,所以很难提供明确的解决方案。 但是,将这些任务的执行更改为单独的线程(如下所示)可能有助于解决问题:

导航观察者:

class RouteTrackerInfo {
  final Route<dynamic>? route;
  final Route<dynamic>? previousRoute;

  RouteTrackerInfo({
    this.route,
    this.previousRoute,
  });
}

class NavigationObserver extends NavigatorObserver {
  final void Function(RouteTrackerInfo info)? onRouteChanged;
  NavigationObserver({
    this.onRouteChanged
  });
  @override
  void didPush(Route route, Route? previousRoute) {
    super.didPush(route, previousRoute);
    onRouteChanged?.call(RouteTrackerInfo(route: route, previousRoute: previousRoute));
  }
}

您的小部件状态:

class _MyAppState extends State<MyApp> {
  static final BehaviorSubject<RouteTrackerInfo> _routeTrackerInfoStream = BehaviorSubject.seeded(RouteTrackerInfo(route: null, previousRoute: null));

  @override
  void initState() {
    super.initState();
    _routeTrackerInfoStream.listen((routeTrackerInfo) {
      print('Route changed: ${routeTrackerInfo.route?.settings.name}');

      NotificationsViewState().updateNotifs(); // "Notifications" page
      NotifScrollContentState().updateNotifs(); // content of the notifications modal
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      ...
      navigatorObservers: [
        NavigationObserver(
          onRouteChanged: (info) {
            _routeTrackerInfoStream.add(info);
          }
        ),
      ],
      ...
    );
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.