Navigator.popUntil 造成的 '!_debugLocked': is not true解决思路

7,164 阅读1分钟

问题描述

用Navigator.popUntil(context,ModalRoute.withName(name));返回时闪退,报错信息类似 '!_debugLocked': is not true

问题定位

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

先进入navigator.dart,错误在这里

Widget build(BuildContext context) {
    assert(!_debugLocked);
}

看下定义

  bool _debugLocked = false; // used to prevent re-entrant calls to push, pop, and friends

阻止重复调用,也就是说,在某个动作完成前再一次调用的时候。网上也有类似的issue,用了延时的方法解决的,通过实验发现,这个并不是我闪退的原因,继续找看下popUntil的定义

 static void popUntil(BuildContext context, RoutePredicate predicate) {
    Navigator.of(context).popUntil(predicate);
  }

---------------------------分割线---------------------------
void popUntil(RoutePredicate predicate) {
    while (!predicate(_history.last))
      pop();
  }

emmm,看下RoutePredicate predicate是什么

 static RoutePredicate withName(String name) {
    return (Route<dynamic> route) {
      return !route.willHandlePopInternally
          && route is ModalRoute
          && route.settings.name == name;
    };
  }

对当前rote做判断是否是即将pop的,与所要寻找的name相同,是否是ModalRoute,这里主要看route.settings.name == name,是否正确,就是说当前stack 即_history中不存在与name相同的route时就会一直pop,再来看pop方法

 if (_history.length > 1) {
        _history.removeLast();
        // If route._navigator is null, the route called finalizeRoute from
        // didPop, which means the route has already been disposed and doesn't
        // need to be added to _poppedRoutes for later disposal.
        if (route._navigator != null)
          _poppedRoutes.add(route);
        _history.last.didPopNext(route);
        for (NavigatorObserver observer in widget.observers)
          observer.didPop(route, _history.last);
        RouteNotificationMessages.maybeNotifyRouteChange(_routePoppedMethod, route, _history.last);
      } else {
        assert(() { _debugLocked = false; return true; }());
        return false;
      }

在遍历到最后一个发现也不是所要寻找的route时就会走else方法,造成_debugLocked = false,之后就报错了。。 经过验证,只要Navigator.popUntil(context,ModalRoute.withName(name))中的name是_history的任何一个都不会闪退,看来问题就是在这里了,果然是源码之下,任何问题都无所遁形,所以说学会看源码还是很重要的