Why classes that accesses the same GlobalKey instance must reside in the same file?

715 views
Skip to first unread message

e.t...@gmail.com

unread,
Mar 23, 2018, 1:52:16 AM3/23/18
to Flutter Dev
Hi,

My question is about the behavior of GlobalKey. Say there's is an instance of GlobalKey<WidgetA> named widgetAKey, and WidgetB would call widgetAKey.currentState.doSomething(). The code worked when all these three components (the var widgetAKey declaration, and classes WidgetA and WidgetB) are on the same file, but no longer the case if any one of them was moved to another file (with proper import). If any of these are not in the same file, widgetAKey.currentState is guaranteed to be NULL.

Here's some code to better illustrate this problem.

Firstly, a working one:

It does very simple thing: when the FAB of the child widget is tapped, it calls a method of parent's state instance to change the primary color of the parent MaterialApp.

Then I moved MyHomePage to another homepage.dart (forgive me for not writing code in the dart way). The app breaks, because appStateKey.currentState is now NULL.


I also tried some other refactorings, like just moving the global key declaration to another file while keeping the two classes on the same file, with no luck. This leads me to believe that GlobalKey won't work unless all related pieces must be kept in one place.

I searched this forum and found a suggestion to use GlobalKey to resolve the issue of "calling setState() on a list from another dart file", albeit not recommended.
 But in that thread Andrew just said that "you *really* don't want to do that", and from my experience it is actually *not* working at all.

To be clear, I have already found a way to better achieve what I wanted to do (without using GlobalKey), but I still want to know why it doesn't work in the first place, so that I would not make the same mistake again. I also want to know better what a GlobalKey is, as it seems inevitable in certain situations.

Thanks you in advance.

Edmund

Ian Hickson

unread,
Mar 23, 2018, 1:58:35 AM3/23/18
to e.t...@gmail.com, Flutter Dev
Try importing local files by using relative paths instead of package: paths. I suspect what's happening is that your main.dart's path is being considered the same as "main.dart" and not "package:blabla/main.dart", so when you import it via package: in the second file, you actually end up instantiating two separate "main.dart"s and therefore two separate global keys.

You can test this theory by printing the key's "hashCode" property as seen from each file. I suspect they will be different (meaning you're actually talking about different objects).

--
You received this message because you are subscribed to the Google Groups "Flutter Dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to flutter-dev...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
--

--
Ian Hickson

😸

Edmund Tam

unread,
Mar 23, 2018, 7:45:30 AM3/23/18
to Flutter Dev
Thank you, it turns out to be exactly what you've said. main.dart has to import "homepage.dart" and not "package:balh/homepage.dart", and homepage.dart must not import main.dart with the "package" directive neither.

Can I put it this way: When importing with the "package" directive Dart perceives it as another "namespace" or "scope" that is different from the one in my application, so that even classes in the imported file will be declared twice?

Finally, are we supposed to always be using relative path to import files locally? If yes, is there a use case of the "package" directive for local library files? Honestly I wasn't aware of the difference as the import syntax is generated automatically using the code completion feature of Flutter plugin in Android Studio. 

Thanks again.

Edmund

Ian Hickson於 2018年3月23日星期五 UTC+8下午1時58分35秒寫道:

Ian Hickson

unread,
Mar 26, 2018, 4:20:39 PM3/26/18
to Edmund Tam, Flutter Dev
On Fri, Mar 23, 2018 at 4:45 AM Edmund Tam <e.t...@gmail.com> wrote:
Thank you, it turns out to be exactly what you've said. main.dart has to import "homepage.dart" and not "package:balh/homepage.dart", and homepage.dart must not import main.dart with the "package" directive neither.

Can I put it this way: When importing with the "package" directive Dart perceives it as another "namespace" or "scope" that is different from the one in my application, so that even classes in the imported file will be declared twice?

Yes, if you import a package in two different ways, they count as two different packages.

 
Finally, are we supposed to always be using relative path to import files locally?

It depends what you mean by "local". What really matters is that you be consistent. The one key to the problem you were running into is that "main.dart" is imported relatively, not as a package, so for anything in that package you want to be using relative imports.

 
If yes, is there a use case of the "package" directive for local library files?

It depends what you mean by "local", really. In the "flutter" package itself, we use relative paths within a directory to emphasise that they are part of the same layer, but across directories we refer to the other files using the package syntax to be consistent with how people outside the package would do it.

 
Honestly I wasn't aware of the difference as the import syntax is generated automatically using the code completion feature of Flutter plugin in Android Studio.

Ah! That is very good to know. Can you file a bug on that?

--

--
Ian Hickson

😸

Edmund Tam

unread,
Mar 27, 2018, 11:02:13 AM3/27/18
to Flutter Dev

Ian Hickson於 2018年3月27日星期二 UTC+8上午4時20分39秒寫道:

It depends what you mean by "local". What really matters is that you be consistent. The one key to the problem you were running into is that "main.dart" is imported relatively, not as a package, so for anything in that package you want to be using relative imports.

It depends what you mean by "local", really. In the "flutter" package itself, we use relative paths within a directory to emphasise that they are part of the same layer, but across directories we refer to the other files using the package syntax to be consistent with how people outside the package would do it.

Just for curiosity, is there any way I could find out that "main.dart" is imported relatively?

Honestly I wasn't aware of the difference as the import syntax is generated automatically using the code completion feature of Flutter plugin in Android Studio.

Ah! That is very good to know. Can you file a bug on that?

Anatoly Pulyaevskiy

unread,
Mar 27, 2018, 4:52:53 PM3/27/18
to Flutter Dev
@Ian

This is why I submitted: https://github.com/flutter/flutter/issues/15748
Moving `main.dart` outside of `lib/` would force people to always use `package:` imports and prevent from stepping into this problem again.

Ian Hickson

unread,
Mar 28, 2018, 1:30:12 PM3/28/18
to Edmund Tam, Flutter Dev
On Tue, Mar 27, 2018 at 8:02 AM Edmund Tam <e.t...@gmail.com> wrote:

Ian Hickson於 2018年3月27日星期二 UTC+8上午4時20分39秒寫道:

It depends what you mean by "local". What really matters is that you be consistent. The one key to the problem you were running into is that "main.dart" is imported relatively, not as a package, so for anything in that package you want to be using relative imports.

It depends what you mean by "local", really. In the "flutter" package itself, we use relative paths within a directory to emphasise that they are part of the same layer, but across directories we refer to the other files using the package syntax to be consistent with how people outside the package would do it.

Just for curiosity, is there any way I could find out that "main.dart" is imported relatively?

It's apparent if you look at how the engine is implemented, but that's not obvious.

 
Honestly I wasn't aware of the difference as the import syntax is generated automatically using the code completion feature of Flutter plugin in Android Studio.

Ah! That is very good to know. Can you file a bug on that?

 
Thanks. 
--

--
Ian Hickson

😸

Ian Hickson

unread,
Mar 28, 2018, 1:33:57 PM3/28/18
to Anatoly Pulyaevskiy, Flutter Dev
On Tue, Mar 27, 2018 at 1:52 PM Anatoly Pulyaevskiy <anatoly.p...@gmail.com> wrote:
@Ian

This is why I submitted: https://github.com/flutter/flutter/issues/15748
Moving `main.dart` outside of `lib/` would force people to always use `package:` imports and prevent from stepping into this problem again.

Ah, that wasn't clear from the PR description.

Realistically though it wouldn't force people to use package:, because they'd just put all their code in "bin" instead. I guess it would force them to use relative paths. But then it would be confusing that packages have to use lib/ and applications bin/, and so on.

We're trying to optimize for less friction when you start, so it's a delicate balance between long-term correctness, avoiding problems like this, and simplicity in the overall structure. I'm not sure where the balance lies exactly.

--

--
Ian Hickson

😸
Reply all
Reply to author
Forward
0 new messages