颤动:从子节点检索顶级状态返回null

Ric*_*ies 2 dart flutter

我正在尝试使用.of()方法获取我的应用程序的顶级状态,类似于Scaffold.of()函数.这是(精简的)代码:

class IApp extends StatefulWidget {    
  @override
  IAppState createState() => new IAppState();

  static IAppState of(BuildContext context) =>
    context.ancestorStateOfType(const TypeMatcher<IAppState>());
}
Run Code Online (Sandbox Code Playgroud)

该应用程序使用runApp(新IApp)启动

此窗口小部件创建一个HomePage:

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      // ommitted: some localization and theming details
      home: new HomePage(),
    );
  }
Run Code Online (Sandbox Code Playgroud)

然后,我尝试从HomePage(StatefulWidget本身)访问状态:

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      // ommited: some Scaffold properties such as AppBar
      // runtimeType not actual goal, but just for demonstration purposes
      body: new Text(IApp.of(context).runtimeType.toString()),
    );
  }
Run Code Online (Sandbox Code Playgroud)

奇怪的是,当我将HomePage的代码放在与 IApp 相同的文件中时,代码可以工作,但只是作为一个额外的类.但是,当我将HomePage 放在一个单独的文件(main.dart和homepage.dart互相导入)中时,IApp.of(context)的返回值为null.

是什么导致这个?我该如何解决?

Rém*_*let 16

TDLR:仅使用导入文件

import 'package:myApp/path/myFile.dart';
Run Code Online (Sandbox Code Playgroud)

从来没有

import './myFile.dart';
Run Code Online (Sandbox Code Playgroud)

这是由于飞镖如何解决进口问题.

您可能只有一个源文件,但在构建期间,存在某种重复项.

假设你正在研究'myApp'.要导入文件,您可以同时执行以下两项操作:

  • import 'relativePath/myFile.dart'
  • import 'package:myApp/path2/myFile.dart'

你认为他们指向同一个文件吗?但不是.其中一个将指向原始来源.而另一个将指向用于构建的临时文件.

当您开始混合两种解决方案时,问题就出现了.因为对于编译器,这两个文件是不同的.这意味着IApp从导入package:myApp/IApp的不等于IApp导入的相同relativePath/myApp/IApp

在您的情况下,您在窗口小部件树中插入了一个IAppfrom,pakage:path但您的IApp.of(context)使用IAppState在本地解析.它们都有不同的runtimeType.因此const TypeMatcher<IAppState>()不会匹配.并且您的函数将返回null.


有一种非常简单的方法来测试这种行为.创建test.dart仅包含的文件

class Test {
}
Run Code Online (Sandbox Code Playgroud)

然后在你main.dart添加以下导入:

import 'package:myApp/test.dart' as Absolute;
import './test.dart' as Relative;
Run Code Online (Sandbox Code Playgroud)

您最终可以通过以下方式测试:

new Relative.Test().runtimeType == new Absolute.Test().runtimeType
Run Code Online (Sandbox Code Playgroud)

剧透:结果是假的