Simon Hutton
Simon Hutton

Reputation: 1777

Flutter Navigator.popUntil failed assertion _debugLocked. What's wrong?

^ ^ ^^ ^ NO! THIS QUESTION DOES NOT HAVE AN ANSWER THERE! ^ ^ ^ ^ ^ ^

I'm having problems with Navigator.popUntil. I wrote a small demo app to show what's happening. Before I post this as a bug, am I using popUntil wrong??

call to popUntil displays

enter image description here

It looks like something is locking up the Navigator (setting _debugLocked) and not releasing it.

main.dart below : (can just be pasted into the Flutter demo app)

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Routing Test Page'),
      onGenerateRoute: (RouteSettings settings) {
        switch (settings.name) {
          case '/':
            return MaterialPageRoute(
              builder: (_) => MyHomePage(title: 'Home Page',),
              settings: settings,
            );
          case '/home':
            return MaterialPageRoute(
              builder: (_) => MyHomePage(title: 'Home Page',),
              settings: settings,
            );
          case '/middlepage':
            return MaterialPageRoute(
              builder: (_) => MiddlePage(),
              settings: settings,
            );
          case '/bottompage':
            return MaterialPageRoute(
              builder: (_) => BottomBage(),
              settings: settings,
            );
          default:
            return null;
        }
      },
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Home Page',
            ),
            OutlineButton(
              child: Text('push MiddlePage()'),
              onPressed: () => Navigator.push(
                context,
                MaterialPageRoute(builder: (context) => (MiddlePage())),
              ),
            ),
            OutlineButton(
              child: Text('pushNamed ''/middlepage'''),
              onPressed: () => Navigator.pushNamed(context, '/middlepage'),
            ),
          ],
        ),
      ),
    );
  }
}

class MiddlePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Middle Page'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Middle Page',style: TextStyle(fontWeight: FontWeight.bold)
            ),
            OutlineButton(
              child: Text('push BottomPage()'),
              onPressed: () => Navigator.push(
                context,
                MaterialPageRoute(builder: (context) => (BottomBage())),
              ),
            ),
            OutlineButton(
              child: Text('pushNamed ''/bottompage'''),
              onPressed: () => Navigator.pushNamed(context, '/bottompage'),
            ),
            OutlineButton(
                child: Text('pop'), onPressed: () => Navigator.pop(context)),
            OutlineButton(
                child: Text('popUntil ''/home'''),
                onPressed: () =>
                    Navigator.popUntil(context, ModalRoute.withName('/home'))),
          ],
        ),
      ),
    );
  }
}

class BottomBage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Bottom page'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Bottom Page', style: TextStyle(fontWeight: FontWeight.bold),
            ),
            OutlineButton(
              child: Text('push ''home'''),
              onPressed: () =>
                  Navigator.pushNamed(context, '/home'),
            ),
            OutlineButton(
                child: Text('pop'),
                onPressed: () =>
                    Navigator.pop(context)),

            OutlineButton(
              child: Text('popUntil ''/home'''),
              onPressed: () =>
                  Navigator.popUntil(context, ModalRoute.withName('/home')),
            ),
            OutlineButton(
              child: Text('popUntil ''/home'' (with Are You Sure box)) '),
              onPressed: () async {
                try {
                  if (await _areYouSureDialog(context)) {
                    Navigator.popUntil(context, ModalRoute.withName('/home'));
                  }
                } catch (e) {
                  debugPrint("exception: $e");
                }
              },
            ),
          ],
        ),
      ),
    );
  }
}

Future<bool> _areYouSureDialog(BuildContext context) async {
  return await showDialog<bool>(
        context: context,
        builder: (BuildContext context) {
          return AlertDialog(
            title: const Text('Pop back?'),
            content: const Text('Are you sure?'),
            actions: <Widget>[
              FlatButton(
                child: const Text('YES'),
                onPressed: () {
                  Navigator.of(context).pop(true);
                },
              ),
              FlatButton(
                child: const Text('NO'),
                onPressed: () {
                  Navigator.of(context).pop(false);
                },
              ),
            ],
          );
        },
      ) ??
      false;
}

Upvotes: 1

Views: 7284

Answers (1)

Darshan
Darshan

Reputation: 11669

I recreated your case. Whenever we want to pop navigation to the home screen (root) from anywhere, there are couple of ways to do it as below:

1.Using .isFirst method:

Navigator.of(context).popUntil((route) => route.isFirst);
  1. Using defaultRouteName:

Navigator.popUntil(context, ModalRoute.withName(Navigator.defaultRouteName));

By providing the context first, the route will ensure that the navigation will pop to the default always.

You can try with either approach. I tested at my end and it works well.

Hope this answers your question.

Upvotes: 8

Related Questions