删除数据后刷新指示器不更新列表
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(),
),
),
我有一个 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(),
),
),