1

我正在 initState 中监听数据库更改(firestore)。在特定更改上,我需要将用户路由到另一个屏幕。

我的 initState 函数:

      @override
  void initState() {
    super.initState();
    FirebaseFirestore.instance
        .collection('groups')
        .where('members', arrayContains: globals.user.userId)
        .limit(1)
        .snapshots()
        .listen((event) {
      event.docs.forEach((doc) {
        Navigator.of(context).pushNamedAndRemoveUntil(
            '/GroupScreen', (Route<dynamic> route) => false);
      });
    });
  }

两种情况

  1. 第一个是数据库更改在用户打开应用程序之前生效。然后当用户打开应用程序时,他直接路由到另一个屏幕,没有任何问题
  2. 另一方面,当应用程序打开并且数据库更改生效时,用户被重定向到另一个屏幕并出现上述错误:

调度程序库捕获的异常在 null 上调用了方法“findAncestorStateOfType”。接收方:null 尝试调用:findAncestorStateOfType()

我不明白为什么错误只在第二种情况下生效。

请帮我弄清楚我做错了什么。提前致谢。

额外信息(完整代码):

class MainScreen extends StatefulWidget {
  @override
  _MainScreen createState() => _MainScreen();
}

class _MainScreen extends State<MainScreen> {
  Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
  final _scaffoldKey = new GlobalKey<ScaffoldState>();
  List<String> favoritGroupsList = List<String>();
  bool isLoading = true;
  Stream _groupsStream;

  @override
  void initState() {
    // TODO: implement initState
    checkFirstScreen();
    _groupsStream = FirebaseFirestore.instance
        .collection('groups')
        .where('guests', arrayContains: globals.user.userId)
        .orderBy('status')
        .snapshots();
    if (_groupsStream != null) {
      FirebaseFirestore.instance
          .collection('groups')
          .where('members', arrayContains: globals.user.userId)
          .limit(1)
          .snapshots()
          .listen((event) {
        event.docs.forEach((doc) {
          joinUserToGroup(context, doc.id);
        });
      });
    }
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) => {
          initFunctions(),
          Network().getAvailableFriends().then((value) => showSnackBar())
        });
  }

  void initFunctions() async {
    await Network().getAllUser();
    await Network().getUser();
    if (this.mounted) {
      setState(() {
        isLoading = false;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async => false,
      child: Scaffold(
        key: _scaffoldKey,
        appBar: AppBar(
        .
        .
        .
      ),
    );
  }

joinUserToGroup(BuildContext context, String groupId) {
    globals.tempGroup.groupId = groupId;
    Navigator.of(context).pushNamedAndRemoveUntil(
        '/GroupScreen', (Route<dynamic> route) => false);
    _groupsStream = null;
  }
}

问题出在 Navigator 中的 joinUserToGroup 函数中。谢谢!

4

4 回答 4

0

你有没有像代码下面的红线这样的错误,因为你的代码在你提供像这个代码这样的正确参数之前不应该工作


joinUserToGroup(BuildContext context, String groupId) {
    globals.tempGroup.groupId = groupId;

   return Navigator.pushNamedAndRemoveUntil(
                    context,
                    '/GroupScreen',
                    (route) => false);
              },
    _groupsStream = null;
  }
}

如果您遇到新错误,我认为这就是使您的应用程序正常工作所需的全部内容,请在评论中添加

于 2020-11-02T22:06:33.790 回答
0

我通过在外面提供 Navigator 来制作你的应用程序,我遇到了同样的错误,因为你在应用程序创建第一个上下文时要求一个新的上下文,MaterialApp并且它在颤动中是非法的,所以你必须通过将它放在里面来分离导航器Widget得到First context 中的上下文然后用于更新State ManagementScreenState Management Package它很容易理解,对于像您这样的复杂应用程序,如果没有状态管理,很难制作,因此以另一种方式,您的代码将永远无法工作,因此请尝试添加更多类并将它们分开并使用状态管理来发送数据和检查逻辑,如果你学习并阅读它们,你将在两到四天内完成它们,我一开始遇到同样的问题,但状态管理解决了这个问题

于 2020-11-02T22:47:35.573 回答
0

您应该等到数据可用,然后将代码放在具有 Future 这样的函数中

Future<viod> someFunction() async{
  FirebaseFirestore.instance
        .collection('groups')
        .where('guests', arrayContains: globals.user.userId)
        .snapshots()
        .listen((event) {
      event.docs.forEach((doc) {
        if (doc['members'].contains(globals.user.userId)) {
          SchedulerBinding.instance.addPostFrameCallback((_) {
            Navigator.of(context).pushNamedAndRemoveUntil(
                '/GroupScreen', (Route<dynamic> route) => false);
          });
        }
      });
    });
}

然后将该函数添加到 initState()

void initState() {
    super.initState();
  someFunction();
  }

我认为这可能是工作

于 2020-11-02T14:25:14.037 回答
0

我发现您的问题与BuildContext上下文有关,您在外部调用 navigatorBuildContext这就是为什么会出现此错误,因此您必须提供上下文,因为没有上下文就无法创建新屏幕,也许此链接可以帮助您方法“findAncestorStateOfType”是在颤振飞镖中调用 null

 void someFunction(BuildContext context) {
  FirebaseFirestore.instance
        .collection('groups')
        .where('guests', arrayContains: globals.user.userId)
        .snapshots()
        .listen((event) {
      event.docs.forEach((doc) {
        if (doc['members'].contains(globals.user.userId)) {
          SchedulerBinding.instance.addPostFrameCallback((_) {
            Navigator.of(context).pushNamedAndRemoveUntil(
                '/GroupScreen', (Route<dynamic> route) => false);
          });
        }
      });
    });
}
void initState() {
    super.initState();
  someFunction();
  }
于 2020-11-02T18:44:22.717 回答