问题描述
我在使用有状态小部件时遇到了一些与 setState 函数相关的问题,这些小部件在定时器的帮助下自行更新.下面的代码显示了 2 个主要类,它们复制了我是如何发现这个错误的.文本小部件"Lorem"应在 10 秒内插入 - 确实如此 - 但从未显示.我尝试调试数组"Items",它确实在 5 秒后包含"lorem"文本小部件,这是应该的."build"函数运行,但对 UI 没有任何影响.
class textList extends StatefulWidget { @override State<StatefulWidget> createState() => new _textListState(); } class _textListState extends State<textList> with TickerProviderStateMixin { List<Widget> items = new List(); Widget lorem = new textClass("Lorem"); Timer timer; @override void initState() { super.initState(); items.add(new textClass("test")); items.add(new textClass("test")); timer = new Timer.periodic(new Duration(seconds: 5), (Timer timer) { setState(() { items.removeAt(0); items.add(lorem); }); }); } @override void dispose() { super.dispose(); timer.cancel(); } @override Widget build(BuildContext context) { Iterable<Widget> content = ListTile.divideTiles( context: context, tiles: items).toList(); return new Column( children: content, ); } } class textClass extends StatefulWidget { textClass(this.word); final String word; @override State<StatefulWidget> createState() => new _textClass(word); } class _textClass extends State<textClass> with TickerProviderStateMixin { _textClass(this.word); String word; Timer timer; @override void initState() { super.initState(); timer = new Timer.periodic(new Duration(seconds: 2), (Timer timer) { setState(() { word += "t"; }); }); } @override void dispose() { super.dispose(); timer.cancel(); } @override Widget build(BuildContext context) { return new Text(word); } }
这不是我发现此错误的原因,但这是复制它的最简单方法.主要思想是:子文本应该不断更新自己(在这种情况下,在最后添加"t"),并且在 5 秒后,它们中的最后一个应该被替换为文本小部件"Lorem",会发生什么在列表中,但不在 UI 中.
推荐答案
问题如下:
- State 不应该有任何构造函数参数.使用 widget 属性来访问关联 StatefulWidget 的最终属性.
- Flutter 正在重用您的 _textClass 实例,因为类名和键匹配.这是一个问题,因为您只在 initState 中设置了 widget.word,因此您没有获取新的 word 配置信息.您可以通过为 StatefulWidget 实例提供唯一键来消除它们的歧义并导致旧的 State 被释放,或者您可以保留旧的 State 并实现 didUpdateWidget 来解决此问题.后一种方法如下所示.
import 'dart:async'; import 'package:flutter/material.dart'; void main() { runApp(new MaterialApp( home: new Scaffold( appBar: new AppBar(title: new Text('Example App')), body: new textList(), ), )); } class textList extends StatefulWidget { @override State<StatefulWidget> createState() => new _textListState(); } class _textListState extends State<textList> with TickerProviderStateMixin { List<Widget> items = new List(); Widget lorem = new textClass("Lorem"); Timer timer; @override void initState() { super.initState(); items.add(new textClass("test")); items.add(new textClass("test")); timer = new Timer.periodic(new Duration(seconds: 5), (Timer timer) { setState(() { items.removeAt(0); items.add(lorem); }); }); } @override void dispose() { super.dispose(); timer.cancel(); } @override Widget build(BuildContext context) { Iterable<Widget> content = ListTile.divideTiles( context: context, tiles: items).toList(); return new Column( children: content, ); } } class textClass extends StatefulWidget { textClass(this.word); final String word; @override State<StatefulWidget> createState() => new _textClass(); } class _textClass extends State<textClass> with TickerProviderStateMixin { _textClass(); String word; Timer timer; @override void didUpdateWidget(textClass oldWidget) { if (oldWidget.word != widget.word) { word = widget.word; } super.didUpdateWidget(oldWidget); } @override void initState() { super.initState(); word = widget.word; timer = new Timer.periodic(new Duration(seconds: 2), (Timer timer) { setState(() { word += "t"; }); }); } @override void dispose() { super.dispose(); timer.cancel(); } @override Widget build(BuildContext context) { return new Text(word); } }