You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修复Flutter中Multiple widgets used the same GlobalKey错误?

修复Flutter中Multiple widgets used the same GlobalKey错误

使用IntelliJ IDEA在安卓手机上运行Flutter项目,首次运行正常,但再次点击运行按钮时,日志出现Multiple widgets used the same GlobalKey错误,部分错误日志如下:

======== Exception caught by widgets library =======================================================
The following assertion was thrown while finalizing the widget tree:
Multiple widgets used the same GlobalKey.

The key [GlobalObjectKey int#371bd] was used by multiple widgets. The parents of those widgets were different widgets that both had the following description:
  IndexPage
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._debugVerifyGlobalKeyReservation.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:flutter/src/widgets/framework.dart:3205:13)
#1      _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:633:13)
#2      BuildOwner._debugVerifyGlobalKeyReservation.<anonymous closure>.<anonymous closure> (package:flutter/src/widgets/framework.dart:3149:20)
#3      _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:633:13)
#4      BuildOwner._debugVerifyGlobalKeyReservation.<anonymous closure> (package:flutter/src/widgets/framework.dart:3144:36)
#5      BuildOwner._debugVerifyGlobalKeyReservation (package:flutter/src/widgets/framework.dart:3213:6)
#6      BuildOwner.finalizeTree.<anonymous closure> (package:flutter/src/widgets/framework.dart:3267:11)
#7      BuildOwner.finalizeTree (package:flutter/src/widgets/framework.dart:3342:8)
#8      WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:1169:19)
#9      RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:468:5)
#10     SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1397:15)
#11     SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1318:9)
#12     SchedulerBinding.scheduleWarmUpFrame.<anonymous closure> (package:flutter/src/scheduler/binding.dart:1040:9)
#13     PlatformDispatcher.scheduleWarmUpFrame.<anonymous closure> (dart:ui/platform_dispatcher.dart:837:16)
#17     _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
(elided 3 frames from class _Timer and dart:async-patch)
====================================================================================================

相关代码

路由代码:

final rootKey = GlobalKey<NavigatorState>();
final _shellKey = GlobalKey<NavigatorState>(debugLabel: "index");

@TypedShellRoute<IndexRoute>(
  routes: <TypedRoute<RouteData>>[
    TypedGoRoute<FirstRoute>(
      path: "/",
    ),
    TypedGoRoute<SecondRoute>(
      path: "/second",
    ),
  ],
)
class IndexRoute extends ShellRouteData {
  static final GlobalKey<NavigatorState> $navigatorKey = _shellKey;

  @override
  Widget builder(BuildContext context, GoRouterState state, Widget navigator) {
    return IndexPage(child: navigator);
  }
}

class FirstRoute extends GoRouteData {
  @override
  Page<void> buildPage(BuildContext context, GoRouterState state) {
    return const NoTransitionPage(child: FirstScreen());
  }
}

class SecondRoute extends GoRouteData {
  @override
  Page<void> buildPage(BuildContext context, GoRouterState state) {
    return const NoTransitionPage(child: SecondScreen());
  }
}

主应用代码:

class App extends StatelessWidget {
  const App({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerConfig: GoRouter(
        initialLocation: "/",
        routes: $appRoutes,
        navigatorKey: rootKey,
        redirect: (context, state) {
          return null;
        },
      ),
    );
  }
}

环境配置:

flutter doctor -v
[✓] Flutter (Channel stable, 3.24.3, on macOS 14.6.1 23G93 darwin-arm64, locale zh-Hant-TW)
    • Flutter version 3.24.3 on channel stable at /Users/...
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 2663184aa7 (5 weeks ago), 2024-09-11 16:27:48 -0500
    • Engine revision 36335019a8
    • Dart version 3.5.3
    • DevTools version 2.37.3

[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
    • Android SDK at /Users/...
    • Platform android-34, build-tools 34.0.0
    • ANDROID_HOME = /Users/...
    • ANDROID_SDK_ROOT = /Users/...
    • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 17.0.10+0-17.0.10b1087.21-11609105)
    • All Android licenses accepted.

[✓] IntelliJ IDEA Community Edition (version 2024.1.6)
    • IntelliJ at /Users/mosil/Applications/IntelliJ IDEA Community Edition 2024.1.6.app
    • Flutter plugin version 82.0.2
    • Dart plugin version 241.18968.26

[✓] Connected device
    • Pixel 4 (mobile)                • 98171FFAZ0038F            • android-arm64  • Android 13 (API 33)

修复方案

错误日志明确指出冲突的Key属于IndexPage的实例,核心原因是**IndexPage内部使用了全局/静态的GlobalKey,热重载/再次运行时,旧的Widget树未完全销毁,新旧IndexPage实例共用同一个GlobalKey**。

按以下步骤修复:

1. 检查并修改IndexPage的Key使用

打开IndexPage的代码,确保它没有使用全局或静态的GlobalKey:

  • 如果IndexPage中定义了静态GlobalKey,直接删除该静态变量,改为使用Widget构造函数传入的key:
class IndexPage extends StatelessWidget {
  final Widget child;
  // 移除静态GlobalKey定义
  const IndexPage({super.key, required this.child});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // 使用widget.key替代静态key
      key: widget.key,
      body: child,
      // 其他代码
    );
  }
}
  • 如果必须为IndexPage指定GlobalKey,在创建IndexPage时每次生成新的实例:
    修改IndexRoute的builder方法:
@override
Widget builder(BuildContext context, GoRouterState state, Widget navigator) {
  // 每次创建IndexPage时生成新的GlobalKey
  return IndexPage(
    key: GlobalKey(),
    child: navigator,
  );
}

2. 优化全局NavigatorKey的生命周期(可选)

如果路由的全局rootKey和_shellKey也存在热重载冲突风险,可将它们从全局变量改为绑定到App的State中:

class App extends StatefulWidget {
  const App({super.key});

  @override
  State<App> createState() => _AppState();
}

class _AppState extends State<App> {
  final _rootKey = GlobalKey<NavigatorState>();
  final _shellKey = GlobalKey<NavigatorState>(debugLabel: "index");

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerConfig: GoRouter(
        initialLocation: "/",
        routes: $appRoutes,
        navigatorKey: _rootKey,
        redirect: (context, state) => null,
      ),
    );
  }
}

注:若使用此方式,需调整IndexRoute中$navigatorKey的赋值逻辑,确保能访问到_shellKey(可通过单例、Provider等方式传递)。

验证修复

修改完成后,再次点击运行按钮,确认错误不再出现。

内容的提问来源于stack exchange,提问作者Ada

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 07:07:03