在QuerySnapshot Firebase Flutter自动增长列表的ForEach循环内进行计算会导致错误的计算-错误的结果 [英] Computing inside a ForEach loop of a QuerySnapshot Firebase Flutter autogrows list, results in wrong computation - wrong results

查看:86
本文介绍了在QuerySnapshot Firebase Flutter自动增长列表的ForEach循环内进行计算会导致错误的计算-错误的结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在遍历querysnapshot以获取用于计算距离的值。计算公式运行良好-在for循环外进行了测试。值/变量不为空(已执行空检查)。对于每次计算,将计算出的数据迭代地传递到列表。日志显示,列表中的数据对于每个完整循环都会加倍-例如,第一个循环计数为60的项目将返回60个计算,第二个刷新输出为120-那样,或者根据加载的项目数随机增加。其次,计算是错误的。尽管这是一种基于等待和同步的方法,但我无法弄清楚为什么答案错误以及如何删除重复项。我确实在每次计算之前清除列表(在foreach循环之前)。
参见下面的代码:

I am iterating through a querysnapshot getting values for which am using to compute distance. The computation formulae is working fine - tested outside the for loop. The value/variables are not null (null checks have been done). The computed data is passed to a list iteratively for every computation. Logs show, the data in the list doubles for every complete loop - for example, first loop for items count of 60 returns 60 computations, second refresh outputs 120 --- like that or some random increase depending on number of items loaded. Secondly, the calculation is wrong. While this is a method based on await and sync, I am unable to figure out why the wrong answer and how to remove duplicates. I do clear the list before each computation (before the foreach loop). See code below:

    Future<List> getDistancesModified() async {
    distanceList.clear();
    var x = await FirebaseFirestore.instance.collection(Str.ITEMS).get();
    if (x != null) {
      x.docs.forEach((doc) {
        itemAddressLat =
            double.tryParse(doc.data()[Str.ITEM_LATITUDE].toString()) ??
                -1.2921;
        itemAddressLong =
            double.tryParse(doc.data()[Str.ITEM_LONGITUDE].toString()) ??
                36.8219;

        distance = distanceBetween(
            itemAddressLat ?? defaultUserLat,
            itemAddressLong ?? defaultUserLong,
            usersCurrentLocationLat ??
                usersCurrentLocationLatFromDb ??
                defaultUserLat,
            usersCurrentLocationLong ??
                usersCurrentLocationLongFromDb ??
                defaultUserLong); //gives wrong answer inside the foreach loop but gives right answer if done separate from the for each loop for single values. The foreach is necessary to get all distances and pass them to a text through a future builder. 

        distance = distance.roundToDouble();
        distanceList.add(formatDistance(distance / 1000));//console prints grows for every rebuild
      });
    }

未来的构建器如下:

child: FutureBuilder(
    future: getDistancesModified(),
    builder: (context, snapshot) {
      if (snapshot.hasData) {
        return Text(
          distanceList.length >
                  index
              ? distanceList[index]
                  .toString()
              : "",
          style: TextStyle(
              color: Colors.black,
              fontSize: 12.0,
              fontWeight:
                  FontWeight.w600),
        );
      } else {
        return Text('Loading...');
      }
    },
  ),

文本上显示的值有误,例如当预计输出200米或3KM时,实际上无法提供1113KM,4096等。

The values displayed on the text are way wrong e.g. when expecting an output of 200 meters or 3KM, it gives 1113KM, 4096 etc practically not possible. the computation is only in the for each loop.

任何帮助将不胜感激。

Any help will be appreciated. This is killing my application.

推荐答案

这个问题困扰了我一段时间,但以下代码有效:

This issue disturbed me for some time, but the below code worked:

    Future<List> getDistances() async {
    distanceList = [];
    for (var i in items) {
      var s;
      var x = i.data()[Str.ITEM_LATITUDE].toString();
      var y = i.data()[Str.ITEM_LONGITUDE].toString();
      double d = distanceBetween(
          double.tryParse(x) ?? usersDefaultCityLat,
          double.tryParse(y) ?? usersDefaultCityLong,
          usersCurrentLocationLat ??
              usersHomeLocationLat ??
              usersDefaultCityLat,
          usersCurrentLocationLong ??
              usersHomeLocationLong ??
              usersDefaultCityLong);
      if (d < 454) {
        s = "Nearby";
      }
      if (d >= 454 && d < 1000) {
        d = d;
        s = d.toStringAsFixed(0) + " M";
      }
      if (d >= 1000) {
        s = (d / 1000).toStringAsFixed(0) + " KM";
      }
      distanceList.add(s);
    }
    return distanceList;
  }

不过,这不是我解决问题的唯一方法。如上所述,还完成了以下操作:

Nevertheless, this cannot be the only way I solved the issue. The following was also done:


  1. 如上所述,我使用了for循环,而不像foreach那样,即使经过适当的等待序列处理也给出了空值,以避免

  1. As is above, I used a for loop unlike the foreach which was giving nulls even with proper await sequencing to avoid evaluating a future and not a value.

返回/设置要用于此函数的值的await函数全部放入另一个异步函数中像下面这样;

The await functions returning/setting values to be used for this function were all put into another async function like below;

  Future<void> setUserLocationAddress() async {
 await getLocationFromLocationPackage();
 await setCountryCapitalCityLatlong();
 await getUserHomeAddress();
 await getDistances();

}

通话在initState处仅用于上述功能:

The call at the initState was only for the function above:

 @override
 void initState() {
 super.initState();
 setUserLocationAddress();
 }



  • 调用Firebase数据库获取项目到列表中一式两份-这是主要的罪魁祸首:我有以下内容:列出项目和列出distanceList,所有这些都得到一个要显示的项目,另一个要获得计算距离的纬度和经度。这导致最终列表中出现重复。

  • The call to the firebase database to get items into a list was in duplicate - this was the main culprit: I hade the following: List items and List distanceList and all were getting the items one for display and one to get the latitudes and longitudes for calculating distances. This led to duplication in the final list.

    与列表的所有距离(注意,保持距离的文本以交错形式包裹网格视图,该网格视图最初已经在DocumentSnapshot的List项之间进行迭代,我还使用相同的索引键在Text Widget上的另一个list distanceList进行迭代-真正的问题。然而,如@jamesdlin指出的那样,请尽可能使用局部变量

    All this distances from a list (note that the text holding the distance was wrapped in a staggered grid view which was already iterating through the items List of DocumentSnapshot while initially, I was also iterating throught another list distanceList on the Text Widget using the same index key - the really issue. Nevertheless as pointed by @jamesdlin, use of local variables where possible.

    FutureBuilder(
     future: getDistances(),
     builder: (context, snapshot) {
       if (snapshot.hasData) {
         return Text(
           distanceList.length >
                   index
               ? distanceList[index]
                   .toString()
               : "",//THIS CHECK WAS NECESSARY AGAINST LIST LENGHTS NOT MATCHING IF ANY
           style: TextStyle(
               color: Colors.black,
               fontSize: 12.0,
               fontWeight:
                   FontWeight.w600),
         );
       } else {
         return Icon(Icons
             .location_searching);
       }
     },
    ),
    



  • 最后,老实说,我不得不把自己的头埋在Flutter Future中-使用await和asnyc来理解所有这些:感谢 https://dart.dev/codelabs/async-await

    我希望这能教给某人,并能帮助任何人,以防他们在侧面交错的网格视图(gridview / listview)中遇到重复的列表,并使用foreach而不是for循环(我无法确定for是否真的解决了这个问题,但是在其他地方也看到过类似的论点,并且很安全,因为无论链式等待的顺序如何,foreach都给出了空值。
    这个问题应该是我提出的类似问题的指针:

    I hope this educates someone and will help anyone in case they run into duplicate lists in side staggered grid views (gridview/listview), and use of foreach as opposed to for loop (I cannot say for sure if the for really solved the problem, but had seen similar argument somewhere else, and am safe because, the foreach gave out nulls no matter the sequence of chained awaits. This question should be a pointer to similar questions I had raised:


    1. 自动计算距地理坐标的距离存储在Firebase Firestore Flutter中的数据

    2. Geolocator使用distanceBetween()给出了错误的距离。Flutter使用链式等待异步方法
      谢谢。 Flutter中的新手,但没有编码:)。

    这篇关于在QuerySnapshot Firebase Flutter自动增长列表的ForEach循环内进行计算会导致错误的计算-错误的结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆