1

我有一个 ArticlesPage 小部件,它有一个定期计时器来再次路由同一页面。这是一种从外部 API 中提取新文章的方法。

为了避免屏幕堆栈中的页面过多,我Navigator.of(context).popUntil((route) => route.isFirst);在 build 方法中使用了所有其他页面。

在定期路由期间,我不断看到以下错误:

未处理的异常:在 dispose() 后调用 setState():_ArticlesPageState#9ae77(生命周期状态:已失效,未安装) E/flutter (19115):如果您在 State 对象上调用 setState() 以获取不再存在的小部件,则会发生此错误出现在小部件树中

我应该如何解决它?

ArticlesPage 小部件:

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,
      );
    },
  );
}
4

2 回答 2

2

我为自己找到的最佳解决方案是通过运行以下代码确保小部件位于小部件树中:

if (this.mounted){
 setState((){
  //Your state change code goes here
 });
}

在 dispose() 之后调用的 setState() 问题的原始答案

于 2020-07-18T01:23:21.613 回答
2

上面的问题是正确的,我只想指出你也应该取消定时器以避免在小部件被释放后不必要的运行

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();
  }

  ....

}
于 2020-07-18T01:59:19.213 回答