Flutter 定期刷新并弹出所有其他页面导致错误
Flutter periodic refresh and popping all other page caused error
我有一个 ArticlesPage 小部件,它有一个定期计时器来再次路由同一页面。这是一种从外部 API.
获取新文章的方法
为了避免屏幕堆栈中有太多页面,我在构建方法中使用 Navigator.of(context).popUntil((route) => route.isFirst);
弹出所有其他页面。
在定期路由期间,我不断看到以下错误:
未处理的异常:setState() 在 dispose() 之后调用:_ArticlesPageState#9ae77(生命周期状态:失效,未安装)
E/flutter (19115):如果您在状态对象上为不再出现在小部件树中的小部件调用 setState(),则会发生此错误
我该如何解决?
文章页面小部件:
class ArticlesPage extends StatefulWidget {
ArticlesPage({Key key}) : super(key: key);
@override
_ArticlesPageState createState() => _ArticlesPageState();
}
class _ArticlesPageState extends State<ArticlesPage> {
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) {
//pop all other pages
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<Offset>(
begin: const Offset(0, 0),
end: Offset.zero,
).animate(animation),
child: child,
);
},
);
}
我为自己找到的最佳解决方案是通过 运行 此代码确保小部件 IS 在小部件树中:
if (this.mounted){
setState((){
//Your state change code goes here
});
}
到dispose()后调用的setState()的问题
上面的问题是正确的,我只是想指出,你也应该取消定时器,以避免在处理小部件后不必要的运行
class _ArticlesPageState extends State<ArticlesPage> {
Timer _timer; //have a reference of your timer
void __refresh() {
Navigator.of(context).push(slideRouteArticles());
}
@override
void initState() {
super.initState();
_timer = Timer.periodic(
Duration(seconds: 5),
(Timer t) {
if(this.mounted) setState(() => __refresh()); //just like the answer of @kovalyovi
}
);
}
@override
void dispose(){
_timer.cancel();
super.dispose();
}
....
}
我有一个 ArticlesPage 小部件,它有一个定期计时器来再次路由同一页面。这是一种从外部 API.
获取新文章的方法为了避免屏幕堆栈中有太多页面,我在构建方法中使用 Navigator.of(context).popUntil((route) => route.isFirst);
弹出所有其他页面。
在定期路由期间,我不断看到以下错误:
未处理的异常:setState() 在 dispose() 之后调用:_ArticlesPageState#9ae77(生命周期状态:失效,未安装) E/flutter (19115):如果您在状态对象上为不再出现在小部件树中的小部件调用 setState(),则会发生此错误
我该如何解决?
文章页面小部件:
class ArticlesPage extends StatefulWidget {
ArticlesPage({Key key}) : super(key: key);
@override
_ArticlesPageState createState() => _ArticlesPageState();
}
class _ArticlesPageState extends State<ArticlesPage> {
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) {
//pop all other pages
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<Offset>(
begin: const Offset(0, 0),
end: Offset.zero,
).animate(animation),
child: child,
);
},
);
}
我为自己找到的最佳解决方案是通过 运行 此代码确保小部件 IS 在小部件树中:
if (this.mounted){
setState((){
//Your state change code goes here
});
}
上面的问题是正确的,我只是想指出,你也应该取消定时器,以避免在处理小部件后不必要的运行
class _ArticlesPageState extends State<ArticlesPage> {
Timer _timer; //have a reference of your timer
void __refresh() {
Navigator.of(context).push(slideRouteArticles());
}
@override
void initState() {
super.initState();
_timer = Timer.periodic(
Duration(seconds: 5),
(Timer t) {
if(this.mounted) setState(() => __refresh()); //just like the answer of @kovalyovi
}
);
}
@override
void dispose(){
_timer.cancel();
super.dispose();
}
....
}