приложение flutter, список, извлеченный из firestore, дублирует его самостоятельно

#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 вызове.