Вопрос или проблема
Вот мой образец репозитория.
Я использую IntellJ IDEA и запускаю его на своем телефоне Android.
Первый запуск проходит нормально.
Если нажать кнопку запуска снова, в логах появится сообщение Multiple widgets used the same GlobalKey
.
Как я это исправил. Спасибо за вашу помощь.
- часть лога ошибок, полный лог в readme моего репозитория.
======== Исключение поймано библиотекой виджетов =======================================================
Следующее утверждение было выброшено при финализации дерева виджетов:
Несколько виджетов использовали один и тот же GlobalKey.
Ключ [GlobalObjectKey int#371bd] использовался несколькими виджетами. Родители этих виджетов были разными виджетами, которые оба имели следующее описание:
IndexPage
GlobalKey может быть указан только на одном виджете за раз в дереве виджетов.
Когда исключение было выброшено, это был стек:
#0 BuildOwner._debugVerifyGlobalKeyReservation.<анонимная замыкание>.<анонимная замыкание>.<анонимная замыкание> (пакет:flutter/src/widgets/framework.dart:3205:13)
#1 _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:633:13)
#2 BuildOwner._debugVerifyGlobalKeyReservation.<анонимная замыкание>.<анонимная замыкание> (пакет:flutter/src/widgets/framework.dart:3149:20)
#3 _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:633:13)
#4 BuildOwner._debugVerifyGlobalKeyReservation.<анонимная замыкание> (пакет:flutter/src/widgets/framework.dart:3144:36)
#5 BuildOwner._debugVerifyGlobalKeyReservation (пакет:flutter/src/widgets/framework.dart:3213:6)
#6 BuildOwner.finalizeTree.<анонимная замыкание> (пакет:flutter/src/widgets/framework.dart:3267:11)
#7 BuildOwner.finalizeTree (пакет:flutter/src/widgets/framework.dart:3342:8)
#8 WidgetsBinding.drawFrame (пакет:flutter/src/widgets/binding.dart:1169:19)
#9 RendererBinding._handlePersistentFrameCallback (пакет:flutter/src/rendering/binding.dart:468:5)
#10 SchedulerBinding._invokeFrameCallback (пакет:flutter/src/scheduler/binding.dart:1397:15)
#11 SchedulerBinding.handleDrawFrame (пакет:flutter/src/scheduler/binding.dart:1318:9)
#12 SchedulerBinding.scheduleWarmUpFrame.<анонимная замыкание> (пакет:flutter/src/scheduler/binding.dart:1040:9)
#13 PlatformDispatcher.scheduleWarmUpFrame.<анонимная замыкание> (dart:ui/platform_dispatcher.dart:837:16)
#17 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
(ущерб 3 фрейма из класса _Timer и 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());
}
}
- MainApp
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 версия 3.24.3 на канале stable по адресу /Users/...
• Upstream repository https://github.com/flutter/flutter.git
• Ревизия фреймворка 2663184aa7 (5 недель назад), 2024-09-11 16:27:48 -0500
• Ревизия движка 36335019a8
• Версия Dart 3.5.3
• Версия DevTools 2.37.3
[✓] Инструменты Android - разработка для устройств Android (версия Android SDK 34.0.0)
• Android SDK по адресу /Users/...
• Платформа android-34, инструменты сборки 34.0.0
• ANDROID_HOME = /Users/...
• ANDROID_SDK_ROOT = /Users/...
• Java binary по адресу: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
• Версия Java OpenJDK Runtime Environment (build 17.0.10+0-17.0.10b1087.21-11609105)
• Все лицензии Android приняты.
[✓] IntelliJ IDEA Community Edition (версия 2024.1.6)
• IntelliJ по адресу /Users/mosil/Applications/IntelliJ IDEA Community Edition 2024.1.6.app
• Версия плагина Flutter 82.0.2
• Версия плагина Dart 241.18968.26
[✓] Подключенное устройство
• Pixel 4 (мобильный) • 98171FFAZ0038F • android-arm64 • Android 13 (API 33)
Я использую IntellJ IDEA и запускаю его на своем телефоне Android.
Первый запуск проходит нормально.
Если нажать кнопку запуска снова, в логах появится сообщение Multiple widgets used the same GlobalKey
.
Ответ или решение
Как исправить ошибку "Multiple widgets used the same GlobalKey" в Flutter
Ошибка "Multiple widgets used the same GlobalKey" возникает в Flutter, когда один и тот же экземпляр GlobalKey
используется более чем одним виджетом одновременно в рамках одного дерева виджетов. Это проблема, которую легко можно решить, но для начала важно понять, как GlobalKey
работает и как они должны быть правильно использованы.
Проблема:
Из вашего описания видно, что вы сталкиваетесь с этой ошибкой после повторного запуска приложения. Это может происходить по следующим причинам:
-
Кэширование состояния: При повторном запуске приложения, виджеты могут быть повторно созданы с прежним состоянием, и если вы используете один и тот же
GlobalKey
для нескольких виджетов, то будет выдана ошибка. -
Неправильное использование ключей:
GlobalKey
должен быть уникальным для каждого виджета. Если вы повторно используете его для другого виджета, это приведет к данному исключению.
Решение:
Чтобы исправить эту проблему, следуйте приведенным ниже шагам:
-
Убедитесь, что
GlobalKey
уникален:
Проверьте, где вы определяетеGlobalKey
и убедитесь, что экземпляры ключа создаются только один раз и не используются повторно. Например, в вашем коде у вас есть:final rootKey = GlobalKey<NavigatorState>(); final _shellKey = GlobalKey<NavigatorState>(debugLabel: "index");
Убедитесь, что эти ключи не используются повторно для других виджетов.
-
Обработка состояния приложения:
Поскольку проблема возникает при повторном запуске, попробуйте использовать кратковременные методы локализации состояния вашего приложения для предотвращения возможной гонки между состоянием виджета и ключами. -
Отладка ключей:
Если вы создаете динамические виджеты, убедитесь, чтоGlobalKey
не привязывается к переменной, которая может изменяться во время управления состоянием. Например, если у вас есть список виджетов, убедитесь, что ключи привязаны к каждому из виджетов индивидуально.Вместо:
GlobalKey<SomeWidget> myKey = GlobalKey<SomeWidget>();
Создавайте ключи в методе создания виджетов, если это возможно, чтобы каждый виджет получал уникальный экземпляр ключа:
Widget build(BuildContext context) { return SomeWidget(key: GlobalKey<SomeWidget>()); }
-
Переход на локальные ключи:
Если возможно, используйтеKey
илиValueKey
вместоGlobalKey
, когда вам не нужно сохранять состояние между пересозданием виджетов.
Проверка:
После внесения изменений, обязательно протестируйте приложение. Запустите его несколько раз и проверьте, исчезла ли ошибка. Проверяйте настройки и строки кода, связанные с использованием GlobalKey
.
Вывод:
Исправление ошибки "Multiple widgets used the same GlobalKey" может требовать внимательного обращения с ключами и соблюдения уникальности. Следуя вышеуказанным рекомендациям и проверяя каждую часть вашего виджетного дерева, вы сможете решить данную проблему.
Если у вас остаются вопросы или требуется дальнейшая помощь, не стесняйтесь делиться дополнительной информацией о вашем коде и конфигурации проекта.