#android #firebase #flutter #mobile #google-cloud-firestore
#Android #firebase #flutter #Мобильный #google-облако-firestore
Вопрос:
У меня есть функция, которая должна извлекать мне список объектов ресторанов из firestore на основе местоположения.
функция отлично выполняет свою работу при первом запуске приложения, но после использования приложения с другого устройства и обновления данных ресторанов в документах firestore я каким-то образом получаю дубликаты элементов списка ресторанов.
вот код для функции, которая извлекает список объектов ресторанов:
Future<void> fetchRestaurantsList() async {
try {
Position position = await Geolocator().getCurrentPosition(
desiredAccuracy:
Platform.isIOS ? LocationAccuracy.lowest : LocationAccuracy.high);
final dbRestaurant = firestore
.collection('testing')
.document('users')
.collection('restaurant');
geo.collection(collectionRef: dbRestaurant)
.within(
center: GeoFirePoint(
position.latitude,
position.longitude
),
radius: 45.0,
field: 'resturantLocation')
.listen((event) {
restaurantList.clear();
await event.forEach((element){
final distance = Distance.getDistanceFromLatLonInKm( // calculating distance for each restaurant
position.latitude,
position.longitude,
element.data['location']['geopoint'].latitude,
element.data['location']['geopoint'].longitude)
restaurantList.add(Restaurant(
id: element.documentID,
logo: element.data['logo'],
name: element.data['name'],
distance: distance ,
));
notifyListeners();
});
});
} catch (e) {
print(e.toString());
}
} finally {
notifyListeners();
}
}
и это страница, которая содержит список: (она находится под родительским виджетом, который содержит другие вкладки)
class RestruntsListTab extends StatefulWidget {
final MainModel model;
RestruntsListTab({@required this.model});
@override
State<StatefulWidget> createState() {
return _RestruntsListTabState();
}
}
class _RestruntsListTabState extends State<RestruntsListTab>
@override
void initState() {
widget.model.fetchRestaurantsList();
widget.model.checkLocationService().then((isActive) {
if (isActive) {
} else {
Scaffold.of(context).showSnackBar(SnackBar(
content: Text(
language.enableLcation,
style: TextStyle(
fontFamily: 'eff', fontSize: 18, fontWeight: FontWeight.bold),
),
backgroundColor: Colors.grey,
));
}
});
super.initState();
}
@override
Widget build(BuildContext context) {
return ScopedModelDescendant<MainModel>(
builder: (context, child, model) {
return ListView.builder(
itemCount:model.restaurantList.length,
itemBuilder: (context,index) {
return Row(
children: <Widget>[
Text(model.restaurantList[index].name),
Text(model.restaurantList[index].distance),
],
)
}
);
})
}
}
это упрощенный код для демонстрации, но фактический код довольно похож.
если вы столкнулись с подобными проблемами, пожалуйста, поделитесь своим опытом.
спасибо вам всем.
Комментарии:
1. Дублируются ли элементы и в Firebase?
2. нет. он дублируется только в списке ресторанов.
3. Лол, как тебе это удалось? Это действительно странно. У меня тоже есть эта проблема, и я потратил много своего времени.
Ответ №1:
убедитесь, что метод fetchRestaurantsList() не вызывается при сборке виджета или он находится в StreamBuilder method…it это потому, что .listen((событие) { этот метод похож на поток, поэтому вам нужно использовать флаг, подобный переменной bool, для запуска кода внутри него, если(mybool==false){// другой код идет …. setste({mybool=true;})}
таким образом, код вызывается только один раз
Комментарии:
1. он вызывается только методом initState() родительского виджета. метод не вызывается ни в функции сборки виджета, ни в StreamBuilder.
2. я добавил флаг с именем onFirstRun, чтобы запустить цикл получения ресторанов только при первом запуске, а также выполнил оператор if, чтобы проверить, существует ли выбранный элемент в списке, для каждой итерации для каждого цикла. Все еще проблема не решена :/
Ответ №2:
Возможно, что-то не так с кодом, но я этого не вижу. Что вы можете попробовать сделать, так это обернуть содержимое forEach
с
if(restaurantList.where((item) => item.id == element.documentID).isEmpty){
}
Это должно отфильтровывать дубликаты.
Комментарии:
1. Я использовал оператор if, чтобы проверить, существует ли выбранный элемент в списке, для каждой итерации цикла for each. Все еще как-то получаете дубликаты
2. Ну, это может означать только то, что их идентификаторы разные, что еще более странно. Попробуйте использовать режим отладки, чтобы установить точки останова и приблизиться к тому, что происходит на самом деле, как в
forEach
вызове.