maeni70
maeni70

Reputation: 183

Flutter: Failed assertion while using navigator.dart

I am new to Flutter and playing around with it. So, please be patient with me.

Following exception is thrown when clicking on a specific menu item of a PopupMenuButton, but always the second time only:

'package:flutter/src/widgets/navigator.dart': Failed assertion: line 1846 pos 12: '!_debugLocked': is not true.

Here the setup:

For specifying the menu items following class has been defined:

class PopupMenuChoice {
  const PopupMenuChoice({this.title, this.pageRoute});

  final String title;
  final MaterialPageRoute pageRoute;
}

Definition of the PopupMenuButton in actions property of an AppBar:

new PopupMenuButton<PopupMenuChoice>(
    itemBuilder: (BuildContext context) {
      return _popupMenus.map((PopupMenuChoice choice) {
        return new PopupMenuItem<PopupMenuChoice>(
          value: choice,
          child: new Text(choice.title),
        );
      }).toList();
    },
    onSelected: _popupMenuSelected,
),

Corresponding Widgets are defined in following class (the AppBar is created in "return new Scaffold" of this class):

class RandomWordsState extends State<RandomWords> {
  final _suggestions = <WordPair>[];
  final _saved = new Set<WordPair>();
  final _popupMenus = <PopupMenuChoice>[];

  ...
}

As you can see there are private variables for holding WordPair objects, but also for the menu choices.

The _popupMenus list is setup in the "build override":

@override
Widget build(BuildContext context) {
    // Setup page routes
    if (_popupMenus.where((p) => p.title == 'Saved Suggestions').length == 0) {
      final _pageRouteSavedSuggestions = new MaterialPageRoute(
        builder: (context) {
          final tiles = _saved.map(
            (pair) {
              return new ListTile(
                title: new Text(
                  pair.asPascalCase,
                  style: _biggerFont,
                ),
              );
            },
          );
          final divided = ListTile
              .divideTiles(
                context: context,
                tiles: tiles,
              )
              .toList();

          return new Scaffold(
            appBar: new AppBar(
              title: new Text('Saved Suggestions'),
            ),
            body: new ListView(children: divided),
          );
        },
      );
      _popupMenus.add(new PopupMenuChoice(
          title: 'Saved Suggestions', pageRoute: _pageRouteSavedSuggestions));
    }

    if (_popupMenus.where((p) => p.title == 'TEST Page').length == 0) {
      final _pageRouteTest = new MaterialPageRoute(
        builder: (context) {
          return new Scaffold(
            appBar: new AppBar(
              title: new Text('TEST Page'),
            ),
            body: new Text('Some content...'),
          );
        },
      );
      _popupMenus.add(
          new PopupMenuChoice(title: 'TEST Page', pageRoute: _pageRouteTest));
    }
    ...

In defined MaterialPageRoute of PopupMenuChoice private variables might be access (e.g. _saved).

Here corresponding event handler for onSelected of PopupMenuButton:

void _popupMenuSelected(PopupMenuChoice choice) {
  Navigator.of(context).push(choice.pageRoute);
}

Can anybody explain why this exception gets thrown? And how can it be prevented?

Thanks, Roger


Additional information from debug console when clicking the second time on specific menu item:

E/flutter (17133): [ERROR:topaz/lib/tonic/logging/dart_error.cc(16)] Unhandled exception: E/flutter (17133): 'package:flutter/src/widgets/routes.dart': Failed assertion: line 177 pos 12: '!_transitionCompleter.isCompleted': Cannot install a MaterialPageRoute after disposing it. E/flutter (17133): #0
_AssertionError._doThrowNew (dart:core/runtime/liberrors_patch.dart:37:39) E/flutter (17133): #1
_AssertionError._throwNew (dart:core/runtime/liberrors_patch.dart:33:5) E/flutter (17133): #2
TransitionRoute.install (package:flutter/src/widgets/routes.dart) E/flutter (17133): #3 ModalRoute.install (package:flutter/src/widgets/routes.dart:740:11) E/flutter (17133): #4 NavigatorState.push (package:flutter/src/widgets/navigator.dart:1444:11) E/flutter (17133): #5 RandomWordsState.build._popupMenuSelected (file:///D:/Flutter%20Projects/startup_namer/lib/main.dart:166:29) E/flutter (17133): #6
_PopupMenuButtonState.showButtonMenu. (package:flutter/src/material/popup_menu.dart) E/flutter (17133): #7
_RootZone.runUnary (dart:async/zone.dart:1381:54) E/flutter (17133): #8 _FutureListener.handleValue (dart:async/future_impl.dart:129:18) E/flutter (17133): #9
Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:633:45) E/flutter (17133): #10
Future._propagateToListeners (dart:async/future_impl.dart:662:32) E/flutter (17133): #11 Future._completeWithValue (dart:async/future_impl.dart:477:5) E/flutter (17133): #12
Future._asyncComplete. (dart:async/future_impl.dart:507:7) E/flutter (17133): #13
_microtaskLoop (dart:async/schedule_microtask.dart:41:21) E/flutter (17133): #14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:50:5)

Upvotes: 14

Views: 18420

Answers (3)

Tasnuva Tavasum oshin
Tasnuva Tavasum oshin

Reputation: 4750

Suppose You have Auth Block , There You have isLoggedIn = false; and a method where signin network call happening :

Suppose you Design the method like this :

logIn(String userId,String Passwrod){
 url ....

if(response.body == 200){
isLoggedIn = true ;
return response.body;
}
}

Now In Your Auth page : The Problem is :

At the Begging of the page class you have checker :

(isLoggedIn){
Navigator.push(context, choice.pageRoute);
}

and When User Click On Submit button there is something like this :

(){
Navigator.push(context, choice.pageRoute);

}

Now The Problem is You get Both Called means LoggedIn = true and then the submit button response here is the problem . remove the initial

(isLoggedIn){
Navigator.push(context, choice.pageRoute);
}

Your Problem Will be Solved.

Use this Checker into Another Page Not at the Login Page

Upvotes: 0

Vraj
Vraj

Reputation: 51

    void _popupMenuSelected(PopupMenuChoice choice) {
      await Future.delayed(const Duration(milliseconds: 100));
      Navigator.push(context, choice.pageRoute);
    }

Upvotes: 5

Denpal Rius
Denpal Rius

Reputation: 61

Have you tried:

void _popupMenuSelected(PopupMenuChoice choice) {
  Navigator.push(context, choice.pageRoute);
}

Upvotes: 2

Related Questions