1

In my app I need execute code before call Navigator.push. But problem is if user press back button before code is execute then there is error:

E/flutter ( 8415): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: Looking up a deactivated widget's ancestor is unsafe. E/flutter ( 8415): At this point the state of the widget's element tree is no longer stable. E/flutter ( 8415): To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling inheritFromWidgetOfExactType() in the widget's didChangeDependencies() method.

Issue is code is still execute and Navigator.push is call even if user press back button (in Widget2).

Here is mwe:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Widget1(),
    );
  }
}

class Widget1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: RaisedButton(
          onPressed: () async {
            await Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => Widget2(),
                ));
          },
        ),
      ),
    );
  }
}

class Widget2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(body: RaisedButton(
      onPressed: () async {
//      Press back button before Future complete
        await Future.delayed(Duration(seconds: 5));
        await Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) => Widget3(),
            ));
      },
    ));
  }
}

class Widget3 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(child: Text('Widget 3'));
  }
}
FlutterFirebase
  • 2,163
  • 6
  • 28
  • 60

1 Answers1

1

There are several things you can do, depending on what you want exactly:

  • To replace current view by new one, preventing your users from navigating back to the previous page, use Navigator.pushReplacement(...)
  • To show a back button in the app bar, but prevent users from going back, wrap your Scaffold with WillPopScope, and make the onWillPop property return a Future.value(false).
  • To simply hide the back button button, go for: AppBar(...,automaticallyImplyLeading: false,...). Users will still be able to go back by pressing the back button in Android, or the swipe gesture in iOS.
drogel
  • 2,567
  • 2
  • 13
  • 22
  • I not want prevent user press back button. I want prevent call to `Navigator.push` in `Widget2` when user press back button after press `RaisedButton` – FlutterFirebase Oct 29 '19 at 12:34
  • I see, I am sorry, I did not understand your question in the first place. I guess what you can try to do is make your `Widget2` stateful, define a boolean variable `didPressBack` that is defaulting to `false`, and wrap your `Widget2`'s Scaffold in a `WillPopScope` widget, that will detect if the user presses the back button. In the `onWillPop` function, change the `didPressBack` variable to `true`, and then, in the `onPress` function of `Widget2`, navigate only if `didPressBack` is `false`. – drogel Oct 29 '19 at 12:42