Flutter periodic refresh and popping all other page caused error

Issue

I have an ArticlesPage widget, which has a periodic timer to route the same page again. This is a way to pull in new articles from external API.

To avoid having too many pages in the screen stack, I pop all other pages using Navigator.of(context).popUntil((route) => route.isFirst); in the build method.

During the periodic routing, I keep seeing the following error:

Unhandled Exception: setState() called after dispose(): _ArticlesPageState#9ae77(lifecycle state: defunct, not mounted)
E/flutter (19115): This error happens if you call setState() on a State object for a widget that no longer appears in the widget tree

How should I fix it?

The ArticlesPage widget:

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

The slideRouteArticles function:

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

Solution

The best solution I found for myself was to make sure that the widget IS in the Widget Tree by running this code:

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

Original answer to the question of setState() called after dispose()

Answered By – kovalyovi

Answer Checked By – David Goodson (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *