Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter: Failed assertion while using navigator.dart

Tags:

flutter

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)

like image 472
maeni70 Avatar asked May 01 '18 13:05

maeni70


2 Answers

    void _popupMenuSelected(PopupMenuChoice choice) {
      await Future.delayed(const Duration(milliseconds: 100));
      Navigator.push(context, choice.pageRoute);
    }
like image 108
Vraj Avatar answered Nov 03 '22 05:11

Vraj


Have you tried:

void _popupMenuSelected(PopupMenuChoice choice) {
  Navigator.push(context, choice.pageRoute);
}
like image 45
Denpal Rius Avatar answered Nov 03 '22 06:11

Denpal Rius