Flutter:使用navigator.dart时失败的断言

14

我刚开始接触Flutter并尝试使用它,所以请耐心等待。

在单击PopupMenuButton的特定菜单项时,将抛出以下异常,但仅限第二次:

'package:flutter/src/widgets/navigator.dart':失败的断言:第1846行第12个位置:'!_debugLocked':不是真的。

这是设置:

为了指定菜单项,定义了以下类:

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

  final String title;
  final MaterialPageRoute pageRoute;
}

在AppBar的actions属性中,PopupMenuButton的定义:

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

以下类中定义了相应的小部件(AppBar是在该类的“return new Scaffold”中创建的):
class RandomWordsState extends State<RandomWords> {
  final _suggestions = <WordPair>[];
  final _saved = new Set<WordPair>();
  final _popupMenus = <PopupMenuChoice>[];

  ...
}

您可以看到,这里有私有变量来保存WordPair对象和菜单选项。

_popupMenus列表在“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));
    }
    ...

在定义的PopupMenuItem的MaterialPageRoute中,可以访问私有变量(例如_saved)。
这里是PopupMenuButton的onSelected对应的事件处理程序:
void _popupMenuSelected(PopupMenuChoice choice) {
  Navigator.of(context).push(choice.pageRoute);
}

有人能解释一下为什么会抛出这个异常吗?它如何避免发生?
感谢, Roger 点击特定菜单项第二次时,从调试控制台获取的其他信息:
[ERROR:topaz/lib/tonic/logging/dart_error.cc(16)] 未处理的异常:'package:flutter/src/widgets/routes.dart': Failed assertion: line 177 pos 12: '!_transitionCompleter.isCompleted': Cannot install a MaterialPageRoute after disposing it.
#0 _AssertionError._doThrowNew (dart:core/runtime/liberrors_patch.dart:37:39) #1 _AssertionError._throwNew (dart:core/runtime/liberrors_patch.dart:33:5) #2 TransitionRoute.install (package:flutter/src/widgets/routes.dart) #3 ModalRoute.install (package:flutter/src/widgets/routes.dart:740:11) #4 NavigatorState.push (package:flutter/src/widgets/navigator.dart:1444:11) #5 RandomWordsState.build._popupMenuSelected (file:///D:/Flutter%20Projects/startup_namer/lib/main.dart:166:29) #6 _PopupMenuButtonState.showButtonMenu. (package:flutter/src/material/popup_menu.dart) #7 _RootZone.runUnary (dart:async/zone.dart:1381:54) #8 _FutureListener.handleValue (dart:async/future_impl.dart:129:18) #9 Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:633:45) #10 Future._propagateToListeners (dart:async/future_impl.dart:662:32) #11 Future._completeWithValue (dart:async/future_impl.dart:477:5) #12 Future._asyncComplete. (dart:async/future_impl.dart:507:7) #13 _microtaskLoop (dart:async/schedule_microtask.dart:41:21) #14 _startMicrotaskLoop (dart:async/schedule_microtask.dart:50:5)

2
你看到这个错误是因为你试图重复使用一个已经被销毁的MaterialPageRoute (这就是为什么第一次可以工作,然后一旦通过关闭退出它进行处置,第二次就会出现此错误)。你可能应该根据需要生成它们,而不是在初始化时一次性生成所有路由。 - Kirollos Morkos
@KirollosMorkos,请看一下,我在这里遇到了相同的错误(https://stackoverflow.com/questions/57033841/showing-error-while-routing-from-one-screen-to-another-in-flutter?noredirect=1#comment100597439_57033841) - Farhana Naaz Ansari
3个回答

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

请始终将您的答案放在上下文中,而不是仅粘贴代码。有关更多详细信息,请参见此处:https://stackoverflow.com/help/how-to-answer。 - gehbiszumeis
太棒了,谢谢你啊。 - Amin Nemati

2

您尝试过以下方法吗:

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

0
假设您有一个Auth Block, 其中您有 isLoggedIn = false; 以及一个进行登录网络调用的方法:

假设您将该方法设计为以下方式:

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

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

现在在您的认证页面上:问题是:
在页面类的开头,您有一个检查器:
(isLoggedIn){
Navigator.push(context, choice.pageRoute);
}

当用户点击提交按钮时,会出现类似以下内容:

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

}

现在的问题是,当你同时获得了Called(意味着LoggedIn = true)和提交按钮的响应时,出现了问题。需要移除初始的

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

您的问题将会得到解决。

将此检查器用于其他页面而非登录页面。


请检查此链接,我遇到了同样的错误,但无法解决。 - user18710300

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接