使用 Firebase 实时数据库在 Flutter 中进行分页 [英] Pagination in Flutter with Firebase Realtime Database
问题描述
我正在尝试使用 Firebase 实时数据库在 Flutter 中进行分页.我已经在 Firestore 中尝试过这个,它在那里工作得很好,但我想要实时数据库.
I am trying to paginate in Flutter with firebase realtime databse. I have tried this in Firestore and it works fine there but I want this with realtime database.
我第一次像这样获取数据.
I am fetching data for the first time like this.
Widget buildListMessage() {
return Flexible(
child: StreamBuilder(
stream: _firebase.firebaseDB
.reference()
.child("chats")
.child("nsbcalculator")
.orderByChild('timestamp')
.limitToFirst(15)
.onValue,
builder: (context, AsyncSnapshot<Event> snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(themeColor)));
} else {
if (snapshot.data.snapshot.value != null) {
listMessage = Map.from(snapshot.data.snapshot.value)
.values
.toList()
..sort(
(a, b) => a['timestamp'].compareTo(b['timestamp']));
if (lastVisible == null) {
lastVisible = listMessage.last;
listMessage.removeLast();
}
}
return ListView.builder(
...
);
}
},
),
);
}
在进行分页之后,我使用了带有 ScrollController 的侦听器
After that to paginate I am using a listener with ScrollController
void _scrollListener() async {
if (listScrollController.position.pixels ==
listScrollController.position.maxScrollExtent) {
_fetchMore();
}
}
最后
_fetchMore() {
_firebase.firebaseDB
.reference()
.child("chats")
.child("nsbcalculator")
.orderByChild('timestamp')
.startAt(lastVisible['timestamp'])
.limitToFirst(5)
.once()
.then((snapshot) {
List snapList = Map.from(snapshot.value).values.toList()
..sort((a, b) => a['timestamp'].compareTo(b['timestamp']));
if (snapList.isNotEmpty) {
print(snapList.length.toString());
if (!noMore) {
listMessage.removeLast();
//Problem is here.....??
setState(() {
listMessage..addAll(snapList);
});
lastVisible = snapList.last;
print(lastVisible['content']);
}
if (snapList.length < 5) {
noMore = true;
}
}
});
}
它作为实时通信工作正常,但是当我尝试在 _fetchMore() setState 中进行分页时,它会刷新整个小部件的状态并再次重新启动 StreamBuilder,并且所有数据仅被新查询替换.我怎样才能防止这种情况??
Its working fine as realtime communication but when I try to paginate in _fetchMore() setState is called but it refreshes the state of whole widget and restarts the StreamBuilder again and all data is replaced by only new query. How can I prevent this??
推荐答案
试试这个
实时列表分页
class FireStoreRepository {
final CollectionReference _chatCollectionReference =
Firestore.instance.collection('Chat');
final StreamController<List<ChatModel>> _chatController =
StreamController<List<ChatModel>>.broadcast();
List<List<ChatModel>> _allPagedResults = List<List<ChatModel>>();
static const int chatLimit = 10;
DocumentSnapshot _lastDocument;
bool _hasMoreData = true;
Stream listenToChatsRealTime() {
_requestChats();
return _chatController.stream;
}
void _requestChats() {
var pagechatQuery = _chatCollectionReference
.orderBy('timestamp', descending: true)
.limit(chatLimit);
if (_lastDocument != null) {
pagechatQuery =
pagechatQuery.startAfterDocument(_lastDocument);
}
if (!_hasMoreData) return;
var currentRequestIndex = _allPagedResults.length;
pagechatQuery.snapshots().listen(
(snapshot) {
if (snapshot.documents.isNotEmpty) {
var generalChats = snapshot.documents
.map((snapshot) => ChatModel.fromMap(snapshot.data))
.toList();
var pageExists = currentRequestIndex < _allPagedResults.length;
if (pageExists) {
_allPagedResults[currentRequestIndex] = generalChats;
} else {
_allPagedResults.add(generalChats);
}
var allChats = _allPagedResults.fold<List<ChatModel>>(
List<ChatModel>(),
(initialValue, pageItems) => initialValue..addAll(pageItems));
_chatController.add(allChats);
if (currentRequestIndex == _allPagedResults.length - 1) {
_lastDocument = snapshot.documents.last;
}
_hasMoreData = generalChats.length == chatLimit;
}
},
);
}
void requestMoreData() => _requestChats();
}
聊天列表视图
class ChatView extends StatefulWidget {
ChatView({Key key}) : super(key: key);
@override
_ChatViewState createState() => _ChatViewState();
}
class _ChatViewState extends State<ChatView> {
FireStoreRepository _fireStoreRepository;
final ScrollController _listScrollController = new ScrollController();
@override
void initState() {
super.initState();
_fireStoreRepository = FireStoreRepository();
_listScrollController.addListener(_scrollListener);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Flexible(
child: StreamBuilder<List<ChatModel>>(
stream: _fireStoreRepository.listenToChatsRealTime(),
builder: (context, snapshot) {
return ListView.builder(
itemCount: snapshot.data.length,
controller: _listScrollController,
shrinkWrap: true,
reverse: true,
itemBuilder: (context, index) {
...
}
);
}
)
),
);
}
void _scrollListener() {
if (_listScrollController.offset >=
_listScrollController.position.maxScrollExtent &&
!_listScrollController.position.outOfRange) {
_fireStoreRepository.requestMoreData();
}
}
}
ChatModel 类
class ChatModel {
final String userID;
final String message;
final DateTime timeStamp;
ChatModel({this.userID, this.message, this.timeStamp});
//send
Map<String, dynamic> toMap() {
return {
'userid': userID,
'message': message,
'timestamp': timeStamp,
};
}
//fetch
static ChatModel fromMap(Map<String, dynamic> map) {
if (map == null) return null;
return ChatModel(
userID: map['userid'],
message: map['message'],
timeStamp: DateTime.fromMicrosecondsSinceEpoch(map['timestamp'] * 1000),
);
}
}
这篇关于使用 Firebase 实时数据库在 Flutter 中进行分页的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!