37

I'm using Flutter. I have a simple app with 3 tabs. There is a RefreshIndicator in each tab with a ListView. The rows are built in another method. This is the code:

 @override
 Widget build(BuildContext context) {
    final GlobalKey<RefreshIndicatorState> _RIKey1 = new GlobalKey<RefreshIndicatorState>();
    final GlobalKey<RefreshIndicatorState> _RIKey2 = new GlobalKey<RefreshIndicatorState>();
    final GlobalKey<RefreshIndicatorState> _RIKey3 = new GlobalKey<RefreshIndicatorState>();

    debugPrint(_RIKey1.toString());
    debugPrint(_RIKey2.toString());
    debugPrint(_RIKey3.toString());
    return new Scaffold(
      body: new DefaultTabController(
        length: 3,
        child: new Scaffold(
          appBar: new AppBar(
            bottom: new TabBar(
              tabs: [
                new Tab(icon: new Icon(Icons.view_list)),
                new Tab(icon: new Icon(Icons.hotel)),
                new Tab(icon: new Icon(Icons.assessment)),
              ],
            ),
            title: new Text('Data'),
          ),
          body: new TabBarView(
            children: [
              new RefreshIndicator(
                key: _RIKey1,
                onRefresh: _actualizoData,
                child: new ListView.builder(
                    padding: new EdgeInsets.only(top: 5.0),
                    itemCount: linea_reservas.length * 2,
                    itemBuilder: (BuildContext context, int position) {
                      if (position.isOdd) return new Divider();
                      final index = position ~/ 2;
                      return _buildRow(index);
                    }),
              ),
              new RefreshIndicator(
                key: _RIKey2,
                onRefresh: _actualizoData,
                child: new ListView.builder(
                    padding: new EdgeInsets.only(top: 8.0),
                    itemCount: linea_inouthouse.length * 2,
                    itemBuilder: (BuildContext context, int position) {
                      if (position.isOdd) return new Divider();
                      final index = position ~/ 2;
                      return _buildRowInOutHouse(index);
                    }),
              ),
              new RefreshIndicator(
                key: _RIKey3,
                onRefresh: _actualizoData,
                child: new ListView.builder(
                    padding: new EdgeInsets.only(top: 5.0),
                    itemCount: linea_ocupacion.length * 2,
                    itemBuilder: (BuildContext context, int position) {
                      if (position.isOdd) return new Divider();
                      final index = position ~/ 2;
                      return _buildRowOcupacion(index);
                    }),
              ),
            ],
          ),
        ),
      ),
    );
  }

I'd added the debugPrints and the output are 6 lines, instead of 3.

I/flutter ( 5252): [LabeledGlobalKey<RefreshIndicatorState>#4d76c]
I/flutter ( 5252): [LabeledGlobalKey<RefreshIndicatorState>#59b9e]
I/flutter ( 5252): [LabeledGlobalKey<RefreshIndicatorState>#2c88b]
I/flutter ( 5252): [LabeledGlobalKey<RefreshIndicatorState>#7bd42]
I/flutter ( 5252): [LabeledGlobalKey<RefreshIndicatorState>#1c984]
I/flutter ( 5252): [LabeledGlobalKey<RefreshIndicatorState>#dbe20]

the app works, but after changing tabs a few times, it crashes with this error:

    I/flutter ( 5252): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter ( 5252): The following assertion was thrown building NotificationListener<KeepAliveNotification>:
I/flutter ( 5252): Multiple widgets used the same GlobalKey.
I/flutter ( 5252): The key [LabeledGlobalKey<RefreshIndicatorState>#7bd42] was used by multiple widgets. The parents of
I/flutter ( 5252): those widgets were:
I/flutter ( 5252): - RepaintBoundary-[<[LabeledGlobalKey<RefreshIndicatorState>#7bd42]>](renderObject:
I/flutter ( 5252):   RenderRepaintBoundary#60a4a DETACHED)
I/flutter ( 5252): - RepaintBoundary-[<[LabeledGlobalKey<RefreshIndicatorState>#7bd42]>](renderObject:
I/flutter ( 5252):   RenderRepaintBoundary#c8cdb NEEDS-LAYOUT NEEDS-PAINT)
I/flutter ( 5252): A GlobalKey can only be specified on one widget at a time in the widget tree.

The keys are generated in the Build method, so, I don't understand why the Multiple widgets used the same GlobalKey error

Why the key is generated again, and why it's not unique? I'm not talking of a thousand intents, the error appears after changing between tabs 4 or 5 times. Thank you for any help.

Alex Angelico
  • 3,710
  • 8
  • 31
  • 49

8 Answers8

28

Could you create your keys "by hand" and use static/constant values? e.g. ...

import 'package:flutter/widgets.dart';

class RIKeys {
  static final riKey1 = const Key('__RIKEY1__');
  static final riKey2 = const Key('__RIKEY2__');
  static final riKey3 = const Key('__RIKEY3__');
}

then in ...

    body: new TabBarView(
            children: [
              new RefreshIndicator(new RefreshIndicator(
// Use the Manual Static Value instead ...
                key: RIKeys.riKey1,
                onRefresh: _actualizoData,
                child: new ListView.builder(
                    padding: new EdgeInsets.only(top: 5.0),
                    itemCount: linea_reservas.length * 2,
                    itemBuilder: (BuildContext context, int position) {
                      if (position.isOdd) return new Divider();
                      final index = position ~/ 2;
                      return _buildRow(index);
                    }),
              ),

I have done this in a similar situation with some success ... especially with redux or other similar patterns ...

babernethy
  • 1,057
  • 1
  • 9
  • 16
  • 14
    how can we access like riKey1.currentState.validate() in case of Form widget validation. – Govind May 17 '20 at 08:57
15

I wanted to create a List of Form Key.

just Change GlobalKey with GlobalObjectKey

like below.

final List<GlobalObjectKey<FormState>> formKeyList = List.generate(10, (index) => GlobalObjectKey<FormState>(index));
Sajjad
  • 2,593
  • 16
  • 26
4

For those who need to continue with GlobalKey:

import 'package:flutter/widgets.dart';

class JosKeys {
  static final josKeys1 = GlobalKey();
  static final josKeys2 = GlobalKey();
}

Using as follows:

[
    CoachTutorialModel(
      ids: "post",
      globalKeys: JosKeys.josKeys1,
      icons: Icon(
        Icons.message,
        color: Colors.white,
        size: 90,
      ),
      ...
    ),

   CoachTutorialModel(
      ids: "post2",
      globalKeys: JosKeys.josKeys2,
      icons: Icon(
        Icons.message,
        color: Colors.white,
        size: 90,
      ),
      ...
    ),
]
Edeson Bizerril
  • 1,595
  • 1
  • 11
  • 12
1

In my case I was adding a key to a widget inside a method that was called in multiple places, the code was not mine so it took a while to debug, just gonna leave this here maybe it helps someone.

Basel Abuhadrous
  • 1,444
  • 1
  • 14
  • 30
1

I had this issue in my flutter project due to Circular dependency. Please check if Widget A imported Widget B, and Widget B imported Windget A

Mithun S
  • 408
  • 8
  • 20
0

I was using a custom widget that wrapped a Container widget. I needed to pass the key from the custom widget to the container, and I was using a parameter key in the wrapper constructor. Ran into the same issue. My fix was to avoid using the word key in the wrapper constructor, changed it to refKey and the error went away.

Waqas ali
  • 61
  • 5
0

I was using riverpod and gorouter, my navigator key was something like this:

final navKeyProv = Provider.autoDispose(
  (_) => GlobalKey<NavigatorState>(),
);

removing auto dispose from the provider fixed it for me:

final navKeyProv = Provider(
  (_) => GlobalKey<NavigatorState>(),
);
Adnan
  • 906
  • 13
  • 30
-1

Same as @babernethy above, you can have

import 'package:flutter/widgets.dart';

class JosKeys {
  static final josKeys1 = const Key('__JosKey1__');
  static final josKeys2 = const Key('__JosKey2__');
}

then do this on one of your Global Keys, make sure to have a different JosKeys.josKeys{number} for each global key

GlobalKey _globalKey = JosKeys.josKeys1;