使用颤振从 Firebase 实时数据库中读取子节点的数量

Posted

技术标签:

【中文标题】使用颤振从 Firebase 实时数据库中读取子节点的数量【英文标题】:read number of children from the firebase realtime database using flutter 【发布时间】:2021-06-30 22:25:45 【问题描述】:

我是 Flutter 的新手,我真的需要帮助解决关于从 Firebase 实时数据库中读取/计算孩子数量的问题。

我使用的数据库有几个类别。 每个类别都有几个案例。

我想要的是从数据库中提取信息,每个类别有多少案例,并在列表中显示此信息。这意味着 - 显示类别的名称AND该类别有多少孩子(案例)(totalCases)...

这是我的代码,我正在努力:

    import '../components/category_list_tile.dart';
    import 'package:firebase_database/ui/firebase_animated_list.dart';
    import 'package:flutter/material.dart';
    import 'package:modal_progress_hud/modal_progress_hud.dart';
    import '../constants.dart';
    import 'package:firebase_core/firebase_core.dart';
    import 'package:firebase_database/firebase_database.dart';
    import 'dart:async';
    
    class ScreenCategoryList extends StatefulWidget 
      static String id = 'screen_category_list';
      final FirebaseApp app;
    
      ScreenCategoryList(this.app);
      @override
      _ScreenCategoryListState createState() => _ScreenCategoryListState();
    
    
    class _ScreenCategoryListState extends State<ScreenCategoryList> 
      final referenceDatabase = FirebaseDatabase.instance;
      final _dbRef = FirebaseDatabase.instance.reference().child("de");
    
      static int number = 100;
      bool showSpinner = false;
      DatabaseReference _databaseReference;
    
      @override
      void initState() 
        final FirebaseDatabase database = FirebaseDatabase(app: widget.app);
        _databaseReference = database.reference().child("de");
        super.initState();
      
    
      @override
      Widget build(BuildContext context) 
        return Container(
          decoration: BoxDecoration(
            gradient: LinearGradient(
              colors: [Colors.white, Colors.white],
            ),
            image: const DecorationImage(
                image: AssetImage("images/background.png"), fit: BoxFit.cover),
          ),
          child: Scaffold(
            backgroundColor: Colors.transparent,
            appBar: AppBar(
              toolbarHeight: 60.0,
              elevation: 0.0,
              backgroundColor: Colors.black12,
              leading: Padding(
                  padding: EdgeInsets.only(left: 12.0, top: 12.0, bottom: 12.0),
                  child: Image(image: AssetImage('images/lexlogo_black.png'))),
              title: Center(
                child: Column(
                  children: [
                    Text(
                      'Kategorien',
                      style: TextStyle(
                          color: kMainDarkColor,
                          fontFamily: 'Roboto',
                          fontSize: 21.0,
                          fontWeight: FontWeight.bold),
                    ),
                  ],
                ),
              ),
              actions: [
                Padding(
                  padding: EdgeInsets.only(right: 8.0),
                  child: IconButton(
                    icon: Icon(Icons.more_vert_rounded),
                    iconSize: 30.0,
                    color: kMainDarkColor,
                    onPressed: () ,
                    //onPressed: onPressMenuButton,
                  ),
                ),
              ],
            ),
            body: ModalProgressHUD(
              inAsyncCall: showSpinner,
              child: FirebaseAnimatedList(
                query: _databaseReference.child('category'),
                itemBuilder: (
                  BuildContext context,
                  DataSnapshot snapshot,
                  Animation<double> animation,
                  int index,
                ) 
                  Future<int> getNumberOfNodes() async 
                    final response = await FirebaseDatabase.instance
                        .reference()
                        .child('de')
                        .child('category')
                        .child('$index')
                        .child('cases')
                        .once();
                    var nodes = [];
                    response.value.forEach((v) => nodes.add(v));
    
                    return nodes.length;
                  
    
                  var myNumber = getNumberOfNodes();
                  int myInt = 99;
                  myNumber.then((value) 
                    myInt = value;
                  );
                  number = myInt;
    
                  return CategoryListTile(
                    title: snapshot.value['name'].toString(),
                    successfulCases: 1,
                    totalCases: number,
                    onTitleClick: () ,
                    onInfoButtonClick: () ,
                  );
                ,
                reverse: false,
                padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 20.0),
              ),
            ),
          ),
        );
      
    

【问题讨论】:

【参考方案1】:

由于您声明了Future&lt;int&gt; getNumberOfNodes() async,因此您需要FutureBuilder 才能显示该值。

类似这样的:

  child: FutureBuilder<int>(
    future: FirebaseDatabase.instance
            .reference()
            .child('de')
            .child('category')
            .child('$index')
            .child('cases')
            .once();
        var nodes = [];
        response.value.forEach((v) => nodes.add(v));
        return nodes.length;
      
    builder: (BuildContext context, AsyncSnapshot<int> snapshot) 
      List<Widget> children;
      if (snapshot.hasData) 
        return Text("Case count: "+snapshot.data);
       else if (snapshot.hasError) 
        return Text('Error: $snapshot.error'),
       else 
        return CircularProgressIndicator();
      
    ,
  )

我没有编译或运行这段代码,所以请把它当作伪代码。如果您在使用此功能时遇到任何错误,请在反馈之前尝试通过搜索错误消息来修复它们。

所以future 是确定值的代码,然后builder 根据值是否可用来呈现正确的UI。你会想用你自己的 UI 替换 Text("Case count: "+snapshot.data),所以 CategoryListTile(...)

【讨论】:

您好弗兰克,感谢您的回答。正如我已经说过的,我对颤动真的很陌生。我真的不明白,如何将未来的构建器集成到我的代码中...... 您是否尝试包含此代码?当你这样做的时候发生了什么?您是否也阅读过FutureBuilder 的内容? api.flutter.dev/flutter/widgets/FutureBuilder-class.html 和 ***.com/questions/51983011/… 是的,我做到了。我花了几乎一整天的时间尝试,但没有任何效果......我想要的是从数据库中提取信息,每个类别有多少案例并在列表中显示这些信息。这意味着 - 显示类别的名称以及该类别有多少孩子(案例)(totalCases)......在Java / android中,我可以通过调用dataSnapshot.getChildrenCount()来获取孩子的数量。它根本不起作用。请帮忙。【参考方案2】:

感谢@Frank van Puffelen 的建议。终于可以读取至少一个类别的孩子的数量了。

必须像这样更改代码:

class _ScreenCategoryListState extends State<ScreenCategoryList> 
  final referenceDatabase = FirebaseDatabase.instance;

  bool showSpinner = false;
  DatabaseReference _databaseReference;

  @override
  void initState() 
    final FirebaseDatabase database = FirebaseDatabase(app: widget.app);
    _databaseReference = database.reference().child("de");
    super.initState();
  

  Future<Map<int, int>> getNumberOfNodes() async 
    Map<int, int> caseNumbers = new Map<int, int>();
    // read number of category nodes
    final categoriesNumbersResponse = await FirebaseDatabase.instance
        .reference()
        .child('de')
        .child('category')
        // .child('0')
        // .child('cases')
        .once();
    var categoryNodes = [];
    categoriesNumbersResponse.value.forEach((v) => categoryNodes.add(v));
    int numberOfCategories = categoryNodes.length;

    //read number of cases in category
    for (int i = 0; i < numberOfCategories; i++) 
      final caseResponse = await FirebaseDatabase.instance
          .reference()
          .child('de')
          .child('category')
          .child('$i')
          .child('cases')
          .once();
      var caseNodes = [];
      caseResponse.value.forEach((v) => caseNodes.add(v));
      int numberOfCases = caseNodes.length;
      caseNumbers[i] = numberOfCases;
    
    return caseNumbers;
  

  @override
  Widget build(BuildContext context) 
    return Container(
      decoration: BoxDecoration(
        gradient: LinearGradient(
          colors: [Colors.white, Colors.white],
        ),
        image: const DecorationImage(
            image: AssetImage("images/background.png"), fit: BoxFit.cover),
      ),
      child: Scaffold(
        backgroundColor: Colors.transparent,
        appBar: AppBar(
          toolbarHeight: 60.0,
          elevation: 0.0,
          backgroundColor: Colors.black12,
          leading: Padding(
              padding: EdgeInsets.only(left: 12.0, top: 12.0, bottom: 12.0),
              child: Image(image: AssetImage('images/lexlogo_black.png'))),
          title: Center(
            child: Column(
              children: [
                Text(
                  'Kategorien',
                  style: TextStyle(
                      color: kMainDarkColor,
                      fontFamily: 'Roboto',
                      fontSize: 21.0,
                      fontWeight: FontWeight.bold),
                ),
              ],
            ),
          ),
          actions: [
            Padding(
              padding: EdgeInsets.only(right: 8.0),
              child: IconButton(
                icon: Icon(Icons.more_vert_rounded),
                iconSize: 30.0,
                color: kMainDarkColor,
                onPressed: () ,
                //onPressed: onPressMenuButton,
              ),
            ),
          ],
        ),
        body: FutureBuilder<Map<int, int>>(
          future: getNumberOfNodes(),
          builder: (BuildContext context,
              AsyncSnapshot<Map<int, int>> casesSnapshot) 
            if (casesSnapshot.hasData) 
              return FirebaseAnimatedList(
                reverse: false,
                padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 20.0),
                query: _databaseReference.child('category'),
                itemBuilder: (
                  BuildContext context,
                  DataSnapshot categorySnapshot,
                  Animation<double> animation,
                  int index,
                ) 
                  int numberOfCases = casesSnapshot.data[index];
                  //print('number  of cases  $_counter, $numberOfCases');
                  return CategoryListTile(
                    title: categorySnapshot.value['name'].toString(),
                    successfulCases: 10,
                    totalCases: numberOfCases,
                    onTitleClick: () ,
                    onInfoButtonClick: () ,
                  );
                ,
              );
             else if (casesSnapshot.hasError) 
              return Center(
                child: Column(
                  children: <Widget>[
                    Icon(
                      Icons.error_outline,
                      color: Colors.red,
                      size: 60,
                    ),
                    Padding(
                      padding: const EdgeInsets.only(top: 16),
                      child: Text('Error: $casesSnapshot.error'),
                    )
                  ],
                ),
              );
             else 
              return Center(
                child: Column(
                  children: <Widget>[
                    SizedBox(
                      child: CircularProgressIndicator(),
                      width: 60,
                      height: 60,
                    ),
                    Padding(
                      padding: EdgeInsets.only(top: 16),
                      child: Text('Awaiting result...'),
                    )
                  ],
                ),
              );
            
          ,
        ),
      ),
    );
  

【讨论】:

以上是关于使用颤振从 Firebase 实时数据库中读取子节点的数量的主要内容,如果未能解决你的问题,请参考以下文章

如何在后台监听firebase实时数据库更新事件并使用颤振自动启动应用程序(如Messenger中的调用功能)?

如何从 Firebase Firestore 获取数据并将其存储在列表中以在颤振小部件中使用?

从Firebase实时数据库读取Android数据并在RecyclerView上显示

Android-从Firebase实时数据库读取数据并显示在RecyclerView上

颤振错误:类型“_Uri”不是“字符串”类型的子类型

颤振 - firebase orderby 首先添加