【发布时间】:2018-08-28 12:00:35
【问题描述】:
从Screen A 导航到Screen B 并单击“取消”按钮返回Screen A 后,我遇到了globalKey 错误。
问题似乎是Screen B 要么是
- A) 未正确处理
- B) 没有做本来可以做的事情
其实我也不知道:
- 如果我只是删除
globalKey的使用,会发生什么坏事? (以便更好地了解基础知识) - 如何正确解决此问题?
StatefulWidget 文档状态:enter link description here
StatefulWidget 在从一个状态对象移动时保持相同的状态对象 如果树的创建者使用 GlobalKey 它的关键。因为一个带有 GlobalKey 的小部件最多只能用于一个 在树中的位置,使用 GlobalKey 的小部件最多有一个 关联元素。 框架利用了这个属性 从树中的一个位置移动具有全局键的小部件时 通过嫁接与该关联的(唯一)子树到另一个 小部件 从旧位置到新位置(而不是 在新位置重新创建子树)。国家对象 与 StatefulWidget 相关联的部分与其余部分一起被嫁接 子树,这意味着状态对象被重用(而不是被 重新创建)在新位置。 但是,为了有资格 嫁接,小部件必须插入到新位置 与从旧位置移除的相同动画帧。
控制台错误输出:
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following assertion was thrown while finalizing the widget tree:
Duplicate GlobalKey detected in widget tree.
The following GlobalKey was specified multiple times in the widget tree. This will lead to parts of
the widget tree being truncated unexpectedly, because the second time a key is seen, the previous
instance is moved to the new location. The key was:
- [LabeledGlobalKey<FormFieldState<String>>#3c76d]
This was determined by noticing that after the widget with the above global key was moved out of its
previous parent, that previous parent never updated during this frame, meaning that it either did
not update at all or updated before the widget was moved, in either case implying that it still
thinks that it should have a child with that global key.
The specific parent that did not update after having one or more children forcibly removed due to
GlobalKey reparenting is:
- Column(direction: vertical, mainAxisAlignment: start, crossAxisAlignment: center, renderObject:
RenderFlex#7595c relayoutBoundary=up1 NEEDS-PAINT)
A GlobalKey can only be specified on one widget at a time in the widget tree.
所以这部分错误输出:
前一个父级在此帧期间从未更新,这意味着它 要么根本没有更新,要么在移动小部件之前更新
让我觉得我的旧有状态小部件有机会做某事(重新定位自身或释放某些东西以正确处理。
这似乎在framework.dart assert(_children.contains(child)) 上失败了:
@override
void forgetChild(Element child) {
assert(_children.contains(child));
assert(!_forgottenChildren.contains(child));
_forgottenChildren.add(child);
}
【问题讨论】:
-
您可能希望使用
popAndPushNamed()或类似名称而不是仅使用pushNamed()在页面之间导航以避免页面被多次添加 -
感谢您的回复。这里有两件事 1) 幸运的是,我刚开始使用 fluro (github.com/goposse/fluro),但我还不知道
pop如何与该库一起工作。 2) 如果此错误暗示Screen A是仍然存在,有没有办法我可以使用那个实例? (我认为错误都来自Screen A。可能是因为有Screen A的原始实例,它正在尝试创建一个新实例 -
这也是我的假设。不过我不知道Fluro。我认为您需要 top pop 活动路线才能返回到前一个路线,或者当您推送新路线时,替换前一个路线,而不是仅添加一个顶部的另一个。
popAndPushNamed()是 Flutter 路由器如何做到的,不知道 Fluro。 -
@GunterZochbauer 是的,就是这样!我不知道小部件处理与“弹出”一条路线有关。不过,我想这是有道理的。我不再懒惰,而是查看了 Fluro 的文档:github.com/goposse/fluro/blob/master/lib/src/… 并设置
replace: true触发了对dispose()的调用,所以我们都很好。谢谢! -
您可以添加一个简短的 Fluro 代码示例作为答案并接受它
标签: flutter