Flutter定期刷新和弹出所有其他页面导致错误。
Flutter定期刷新和弹出所有其他页面导致错误。
我有一个ArticlesPage小部件,它有一个定时器来周期性地重新路由相同的页面。这是从外部API获取新文章的一种方式。
为了避免在屏幕栈中有太多页面,我在构建方法中使用Navigator.of(context).popUntil((route) => route.isFirst);
来弹出所有其他页面。
在周期性路由过程中,我一直看到以下错误:
Unhandled Exception: setState() called after dispose(): _ArticlesPageState#9ae77(lifecycle state: defunct, not mounted)
E/flutter (19115): 如果您在不再出现在小部件树中的小部件的State对象上调用setState(),则会出现此错误
我该如何解决它?
ArticlesPage小部件:
class ArticlesPage extends StatefulWidget {
ArticlesPage({Key key}) : super(key: key);
@override
_ArticlesPageState createState() => _ArticlesPageState();
}
class _ArticlesPageState extends State
void __refresh() {
Navigator.of(context).push(slideRouteArticles());
}
@override
void initState() {
super.initState();
new Timer.periodic(
Duration(seconds: 5),
(Timer t) => setState(() {
__refresh();
}));
}
@override
Widget build(BuildContext context) {
//弹出所有其他页面
Navigator.of(context).popUntil((route) => route.isFirst);
return Scaffold(
drawer: MenuDrawerStatefulWidget(),
appBar: MyAppBar(),
body: RefreshIndicator(
onRefresh: () async {
__refresh();
},
child: Container(
color: BG_COLOR,
padding: EdgeInsets.fromLTRB(LR_SPACE, 20, LR_SPACE, 0),
child: ArticleListStatefulWidget(key: UniqueKey())),
),
);
}
}
slideRouteArticles函数:
Route slideRouteArticles() {
return PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) => ArticlesPage(key: UniqueKey(),),
transitionsBuilder: (context, animation, secondaryAnimation, child) {
return SlideTransition(
position: Tween
begin: const Offset(0, 0),
end: Offset.zero,
).animate(animation),
child: child,
);
},
);
}
Flutter周期性刷新和弹出所有其他页面导致错误的问题出现的原因是setState在组件被销毁后仍然被调用。该问题的解决方法是在调用setState之前,先判断组件是否被挂载,如果组件已经被销毁,则不执行setState操作。
解决方法的具体代码如下:
if (this.mounted){
setState((){
//Your state change code goes here
});
}
以上代码会在调用setState之前,先判断组件是否被挂载,如果组件已经被销毁,则不执行setState操作。该解决方法可以避免在组件被销毁后调用setState导致的错误。
该解决方法来源于Stack Overflow上的原始答案,对于问题“setState() called after dispose()”的回答。原始答案指出,由于setState是由Flutter内部调用的,因此原先提出的解决方案并不起作用。
Flutter周期性刷新和弹出其他页面导致错误的问题的原因是在组件被销毁后,定时器仍然继续运行,导致在刷新页面时出现错误。为了解决这个问题,需要在组件被销毁时取消定时器的运行。
解决方法如下:
在组件的状态类中,添加一个定时器的引用变量_timer,并在initState方法中初始化它。然后,在__refresh方法中执行页面刷新的操作。在定时器的回调函数中,判断组件是否被挂载(mounted),如果是则调用setState方法刷新页面。
最后,在dispose方法中取消定时器的运行。
以下是具体的代码实现:
class _ArticlesPageState extends State<ArticlesPage> {
Timer _timer; // 定义一个定时器的引用变量
void __refresh() {
Navigator.of(context).push(slideRouteArticles()); // 页面刷新的操作
}
void initState() {
super.initState();
_timer = Timer.periodic(
Duration(seconds: 5),
(Timer t) {
if(this.mounted) setState(() => __refresh()); // 判断组件是否被挂载,如果是则刷新页面
}
);
}
void dispose(){
_timer.cancel(); // 取消定时器的运行
super.dispose();
}
// ...
}
通过以上的代码实现,解决了Flutter周期性刷新和弹出其他页面导致错误的问题。