Как я исправляю проблему с использованием нескольких виджетов одного GlobalKey

Вопрос или проблема

Вот мой образец репозитория.
Я использую 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 работает и как они должны быть правильно использованы.

Проблема:

Из вашего описания видно, что вы сталкиваетесь с этой ошибкой после повторного запуска приложения. Это может происходить по следующим причинам:

  1. Кэширование состояния: При повторном запуске приложения, виджеты могут быть повторно созданы с прежним состоянием, и если вы используете один и тот же GlobalKey для нескольких виджетов, то будет выдана ошибка.

  2. Неправильное использование ключей: GlobalKey должен быть уникальным для каждого виджета. Если вы повторно используете его для другого виджета, это приведет к данному исключению.

Решение:

Чтобы исправить эту проблему, следуйте приведенным ниже шагам:

  1. Убедитесь, что GlobalKey уникален:
    Проверьте, где вы определяете GlobalKey и убедитесь, что экземпляры ключа создаются только один раз и не используются повторно. Например, в вашем коде у вас есть:

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

    Убедитесь, что эти ключи не используются повторно для других виджетов.

  2. Обработка состояния приложения:
    Поскольку проблема возникает при повторном запуске, попробуйте использовать кратковременные методы локализации состояния вашего приложения для предотвращения возможной гонки между состоянием виджета и ключами.

  3. Отладка ключей:
    Если вы создаете динамические виджеты, убедитесь, что GlobalKey не привязывается к переменной, которая может изменяться во время управления состоянием. Например, если у вас есть список виджетов, убедитесь, что ключи привязаны к каждому из виджетов индивидуально.

    Вместо:

    GlobalKey<SomeWidget> myKey = GlobalKey<SomeWidget>();

    Создавайте ключи в методе создания виджетов, если это возможно, чтобы каждый виджет получал уникальный экземпляр ключа:

    Widget build(BuildContext context) {
       return SomeWidget(key: GlobalKey<SomeWidget>());
    }
  4. Переход на локальные ключи:
    Если возможно, используйте Key или ValueKey вместо GlobalKey, когда вам не нужно сохранять состояние между пересозданием виджетов.

Проверка:

После внесения изменений, обязательно протестируйте приложение. Запустите его несколько раз и проверьте, исчезла ли ошибка. Проверяйте настройки и строки кода, связанные с использованием GlobalKey.

Вывод:

Исправление ошибки "Multiple widgets used the same GlobalKey" может требовать внимательного обращения с ключами и соблюдения уникальности. Следуя вышеуказанным рекомендациям и проверяя каждую часть вашего виджетного дерева, вы сможете решить данную проблему.

Если у вас остаются вопросы или требуется дальнейшая помощь, не стесняйтесь делиться дополнительной информацией о вашем коде и конфигурации проекта.

Оцените материал
Добавить комментарий

Капча загружается...