调试帮助:Flutter StatefulWidget 在滚动出视图后不保持状态
DEBUG HELP: Flutter StatefulWidget doesn't maintain state(s) after scrolled out of view
我正在玩一个简单的应用程序来学习 Flutter。这是 UI:
的结构
app -- MaterialApp -- HomeScreen (stateful)
|- ListView -- PlaceWidget (stateful)
|- ListTile
PlaceWidget object 基本上构建和 returns 一个 ListTile;它唯一的额外职责是跟踪 favorited
状态并相应地构建 ListTile 的 UI。
源码为here,包括两个文件:
main.dart
对于整个应用,
places.dart
用于 http 请求
这是应用程序的行为方式:https://gfycat.com/FineBelovedLeafhopper
从表面上看,当滚出视图时 object 的状态似乎丢失了,但一些调试日志告诉我情况并非如此。
假设我最喜欢 Oto Sushi 然后滚动它 off-screen 但保留指向状态 object 的指针,object 的 favorited
状态仍将是 true
。然而,object 本身(属于 class _PlaceWidgetState
)据报道为 defunct, not mounted
。
我无法再与那个 object 互动。如果我再点击一次 Oto Sushi,它将创建一个新状态 object 并将 object 的 favorited
状态设置为 true
和以前一样。
只要我不滚动 Oto Sushi off-screen,我就可以取消收藏,一切正常。
我设法找到了 TextInputField
和 ExpansionTile
的类似问题(例如 ),但我不知道如何将这些问题的解决方案转化为这个问题。
因此,撇开体系结构讨论不谈,问题的原因在于您如何构建 State
对象。通过构造函数传递数据,您可以确保每次重建小部件时,它们的状态都会被重置。
class PlaceWidget extends StatefulWidget {
@override
_PlaceWidgetState createState() {
return new _PlaceWidgetState(place, false); // woops, always unchecked
}
final Place place;
PlaceWidget(this.place, {Key key}) : super(key: key);
}
class _PlaceWidgetState extends State<PlaceWidget> { ... }
不要这样做,而是使用状态小部件中的 widget
getter 来访问 place
成员。还要确保您仅在状态小部件内初始化 checked
状态 - 或者从此处的某些外部源获取它。
class _PlaceWidgetState extends State<PlaceWidget> {
bool _isChecked = false; // only store state in State
Widget build() {
final Place place = widget.place;
// build your stuff.
}
}
现在您的小部件不断重建的原因是在 ListView
中,屏幕外的小部件可能会被销毁 - 它是为非常大的列表设计的。为防止这种情况,您还可以使用 KeepAlive
小部件。
我正在玩一个简单的应用程序来学习 Flutter。这是 UI:
的结构app -- MaterialApp -- HomeScreen (stateful)
|- ListView -- PlaceWidget (stateful)
|- ListTile
PlaceWidget object 基本上构建和 returns 一个 ListTile;它唯一的额外职责是跟踪 favorited
状态并相应地构建 ListTile 的 UI。
源码为here,包括两个文件:
main.dart
对于整个应用,places.dart
用于 http 请求
这是应用程序的行为方式:https://gfycat.com/FineBelovedLeafhopper
从表面上看,当滚出视图时 object 的状态似乎丢失了,但一些调试日志告诉我情况并非如此。
假设我最喜欢 Oto Sushi 然后滚动它 off-screen 但保留指向状态 object 的指针,object 的 favorited
状态仍将是 true
。然而,object 本身(属于 class _PlaceWidgetState
)据报道为 defunct, not mounted
。
我无法再与那个 object 互动。如果我再点击一次 Oto Sushi,它将创建一个新状态 object 并将 object 的 favorited
状态设置为 true
和以前一样。
只要我不滚动 Oto Sushi off-screen,我就可以取消收藏,一切正常。
我设法找到了 TextInputField
和 ExpansionTile
的类似问题(例如
因此,撇开体系结构讨论不谈,问题的原因在于您如何构建 State
对象。通过构造函数传递数据,您可以确保每次重建小部件时,它们的状态都会被重置。
class PlaceWidget extends StatefulWidget {
@override
_PlaceWidgetState createState() {
return new _PlaceWidgetState(place, false); // woops, always unchecked
}
final Place place;
PlaceWidget(this.place, {Key key}) : super(key: key);
}
class _PlaceWidgetState extends State<PlaceWidget> { ... }
不要这样做,而是使用状态小部件中的 widget
getter 来访问 place
成员。还要确保您仅在状态小部件内初始化 checked
状态 - 或者从此处的某些外部源获取它。
class _PlaceWidgetState extends State<PlaceWidget> {
bool _isChecked = false; // only store state in State
Widget build() {
final Place place = widget.place;
// build your stuff.
}
}
现在您的小部件不断重建的原因是在 ListView
中,屏幕外的小部件可能会被销毁 - 它是为非常大的列表设计的。为防止这种情况,您还可以使用 KeepAlive
小部件。