删除数据后刷新指示器不更新列表

Refresh Indicator does not update a list after deleting data

我有一个 FutureBuilder 从 Firestore 获取特定项目并将它们返回到列表中。为了更新这个列表,我添加了 RefreshIndicator。当将某些内容添加到列表中并刷新它时,它可以正常工作并显示该项目。当我从列表中删除一个项目时出现问题,它加载但列表保持不变。

这是我的小部件:

@override
 void initState() {
   super.initState();
   userFuture = getCollectionItems();
 }

Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      body: Column(
        children: [
          Container(
            margin: EdgeInsets.only(top: 5.5),
            padding: EdgeInsets.only(left: 17, right: 17),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.start,
              children: [
                Text(
                  "Collection",
                  style: TextStyle(
                    fontFamily: 'Montserrat',
                    fontSize: 28,
                    fontWeight: FontWeight.w800,
                  ),
                ),
              ],
            ),
          ),
          createGridAndList(),
          Expanded(
            child: RefreshIndicator(
              onRefresh: () => getCollectionItems(),
              child: displayCollection(),
            ),
          )
        ],
      ),
    );
  }

当我重新启动应用程序或转到另一个页面并返回 pushNamedRemoveUntil 列表正确更新时,这表明查询正在运行。

getCollectionItems() 和 displayCollection():

getCollectionItems() async {
    QuerySnapshot querySnapshot = await Firestore.instance
        .collection("users")
        .document(_userId)
        .collection("userCollection")
        .getDocuments();

    List<Users> collectionID = [];
    for (DocumentSnapshot item in querySnapshot.documents) {
      var data = item.data;

      Users user = Users();
      user.id = data["id"];

      collectionID.add(user);
    }

    final collectionIDs = collectionID.map((doc) => doc.id).toList();

    var splitCollection = partition<dynamic>(collectionIDs, 10);

    for (int i = 0; i < splitCollection.length; i++) {
      QuerySnapshot querySnapshotCollections = await Firestore.instance
          .collection('items')
          .where('itemId', whereIn: splitCollection.elementAt(i))
          .orderBy('timestamp', descending: true)
          .getDocuments();

      setState(() {
        countItem = querySnapshotCollections.documents.length;
        itemsList = querySnapshotCollections.documents
            .map((documentSnapshot) =>
                CollectionItem.fromDocument(documentSnapshot))
            .toList();
      });
    }
  }


displayCollection() {
    return FutureBuilder(
        future: userFuture,
        builder: (context, snapshot) {
          if (snapshot.connectionState != ConnectionState.done) {
            return Padding(
              padding: EdgeInsets.only(top: 20),
              child: SizedBox(
                child: CircularProgressIndicator(
                  valueColor: new AlwaysStoppedAnimation<Color> 
                   (Colors.grey),
                ),
                width: 20.0,
                height: 20.0,
              ),
            );
          }
          if (itemsList == null) {
            return Container(
              padding: EdgeInsets.only(top: 20),
              child: SizedBox(
                child: CircularProgressIndicator(
                  valueColor: new AlwaysStoppedAnimation<Color> 
                   (Colors.grey),
                ),
                width: 20.0,
                height: 20.0,
              ),
            );
          } else if (itemsList.isEmpty) {
            return ListView(
              physics: const BouncingScrollPhysics(
                  parent: AlwaysScrollableScrollPhysics()),
              children: [
                Center(
                  child: Container(
                    padding: EdgeInsets.only(
                        top: MediaQuery.of(context).size.width * 0.50,
                        left: 17,
                        right: 17),
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        Text(
                          "Nothing here.",
                          style: TextStyle(
                              fontFamily: 'Montserrat',
                              fontSize: 13,
                              color: Color(0xff9e9999),
                              fontWeight: FontWeight.w500),
                          textAlign: TextAlign.center,
                        ),
                      ],
                    ),
                  ),
                ),
              ],
            );
          } else if (itemOrientation == "grid") {
            List<GridTile> gridTilesList = [];
            itemsList.forEach((eachItem) {
              gridTilesList.add(GridTile(child: 
              CollectionItemTile(eachItem)));
            });
            return GridView.count(
              crossAxisCount: 2,
              padding: EdgeInsets.fromLTRB(10, 15, 10, 0),
              childAspectRatio: 3 / 2,
              mainAxisSpacing: 15,
              crossAxisSpacing: 10,
              shrinkWrap: true,
              physics: const BouncingScrollPhysics(
                  parent: AlwaysScrollableScrollPhysics()),
              children: gridTilesList,
            );
          } else {
            return Container(
              padding: EdgeInsets.only(bottom: 15),
              child: ListView(
                  padding: EdgeInsets.all(0.0),
                  shrinkWrap: true,
                  physics: const BouncingScrollPhysics(
                      parent: AlwaysScrollableScrollPhysics()),
                  children: itemsList),
            );
          }
        });
  }

我尝试了几种方法,切换到 Stream(它没有用),向 Widget 本身添加了另一个 setState,重建了 类 但问题仍然存在。

您的 Firestore 查询可能正在从缓存中读取。尝试禁用持久性。 Official Tutorial

FirebaseFirestore.instance.settings = Settings(persistenceEnabled: false);

或者如果要清除任何持久化数据,您可以调用 clearPersistence() 方法。

await FirebaseFirestore.instance.clearPersistence();

Hmmm, your displayCollection widget is displaying data based on userFuture, but halfway through you using itemList instead, and your onRefresh function is updating the itemList but not userFuture.

I won't do exactly like you do, but i refactored a bit.

You can try something like this, i didn't test it but let me know if it works

// I changed `userFuture` to `futureItems`
Future<List<CollectionItem>> futureItems; 

@override
void initState() {
  super.initState();
  futureItems = getCollectionItems();
}

Future<List<CollectionItem>> getCollectionItems() async {
  // ... Do your query here

  return querySnapshotCollections.documents.map((documentSnapshot) {
    return CollectionItem.fromDocument(documentSnapshot);
  }).toList();
}

Future<void> refreshCollectionItems() async {
  setState(() {
    // This will update the futureItems
    futureItems = getCollectionItems(); 
  });
}

Widget displayCollection() {
  return FutureBuilder<List<CollectionItem>>(
    future: futureItems,  // The data returned will be inside `snapshot` below
    builder: (context, snapshot) {
      if (snapshot?.hasData ?? false) {
        List<CollectionItem> items = snapshot.data; // This is the return value from `futureItems`

        return RefreshIndicator(
          onRefresh: refreshCollectionItems,
          child: ListView.builder(
            itemCount: items.length, // This is how to get the length, so no need to use `countItem`
            itemBuilder: (context, index){
              CollectionItem item = items[index];

              return // ...Display your widget with item data
            },
          ),
        );
      }

      return // Display widget to handle loading/error/no data
    },
  );
}

Plus it is important to define the return type of a function so that you will know what you will get after executing a function.

解决此问题的最简单方法之一是在刷新时重新设置状态。

                Expanded(
                  child: RefreshIndicator(
                    onRefresh: () {            
                      getCollectionItems();
                      setState(() {
                        userFuture = getCollectionItems();
                      });
                    },
                    child: displayCollection(),
                  ),
                ),