在QuerySnapshot Firebase Flutter自动生成列表的ForEach循环中进行计算会导致错误的计算



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

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等实际上是不可能的。计算仅在for每个循环中进行。

任何帮助都将不胜感激。这正在扼杀我的应用程序。

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

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;
}

然而,这并不是我解决问题的唯一途径。还进行了以下操作:

  1. 如上所述,我使用了一个与foreach不同的for循环,foreach即使有适当的等待顺序也会给出null,以避免评估未来而不是值。

  2. 等待函数返回/设置用于该函数的值都被放入另一个异步函数中,如下所示;

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

    }

  3. initState上的调用仅用于上面的函数:

    @override
    void initState() {
    super.initState();
    setUserLocationAddress();
    }
    
  4. 对firebase数据库的调用是重复的,这是罪魁祸首:我得到了以下内容:list items和list distanceList,所有人都得到了项目,一个用于显示,另一个用于获取计算距离的纬度和经度。这导致了最后清单的重复。

  5. 所有这些距离列表(注意,保持距离的文本被包裹在交错的网格视图中,该视图已经在DocumentSnapshot的项目列表中迭代,而最初,我也在使用相同的索引键迭代文本小部件上的另一个列表距离列表,这才是真正的问题。然而,正如@jamesdlin所指出的,尽可能使用局部变量。

    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);
    }
    },
    ),
    
  6. 最后,老实说,我不得不埋头于Flutter Future——使用wait和asnyc来理解这一切:感谢https://dart.dev/codelabs/async-await

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

  1. 根据Firebase Firestore Flutter中存储的地理坐标数据自动计算距离
  2. Geolocator使用distanceBetween((给出错误的距离带有链式等待异步方法的Flutter非常感谢。Flutter中的新bie,但编码中没有:(

最新更新