基于Firebase实时数据库的颤振分页
我正试图用firebase实时数据库在Flatter中分页。 我在Firestore中尝试过这个,它在那里工作得很好,但我想用实时数据库 我第一次像这样获取数据基于Firebase实时数据库的颤振分页,firebase,firebase-realtime-database,pagination,flutter,Firebase,Firebase Realtime Database,Pagination,Flutter,我正试图用firebase实时数据库在Flatter中分页。 我在Firestore中尝试过这个,它在那里工作得很好,但我想用实时数据库 我第一次像这样获取数据 Widget buildListMessage() { return Flexible( child: StreamBuilder( stream: _firebase.firebaseDB .reference() .child("chats")
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(
...
);
}
},
),
);
}
最后
_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;
}
}
});
}
\u fetchMore(){
_firebase.firebaseDB
.reference()
.child(“聊天”)
.child(“NSB计算器”)
.orderByChild(“时间戳”)
.startAt(lastVisible['timestamp'])
.limitToFirst(5)
.一次
.然后((快照){
List snapList=Map.from(snapshot.value).values.toList()
…排序((a,b)=>a['timestamp'].比较(b['timestamp']);
if(snapList.isNotEmpty){
打印(snapList.length.toString());
如果(!noMore){
listMessage.removeLast();
//问题就在这里。。。。。??
设置状态(){
listMessage..addAll(快照列表);
});
lastVisible=snapList.last;
打印(lastVisible['content']);
}
如果(snapList.length<5){
noMore=真;
}
}
});
}
它与实时通信一样工作正常,但当我尝试在_fetchMore()中分页时,会调用setState,但它会刷新整个小部件的状态,并再次重新启动StreamBuilder,所有数据都会被替换为仅新的查询。如何防止这种情况发生???调用
setState
将重新绘制整个小部件和列表视图。现在,因为您提供了提供第一页的蒸汽,所以在重新绘制之后,它只加载它。为了避免这种情况,您可以使用自己的流并向其提供新内容。然后您的StreamBuilder
将自动处理更新
您需要将项目的完整列表存储为一个单独的变量,进行更新,然后放入流中
final _list = List<Event>();
final _listController = StreamController<List<Event>>.broadcast();
Stream<List<Event>> get listStream => _listController.stream;
@override
void initState() {
super.initState();
// Here you need to load your first page and then add to your stream
...
_list.addAll(firstPageItems);
_listController.sink.add(_list);
}
@override
void dispose() {
super.dispose();
}
Widget buildListMessage() {
return Flexible(
child: StreamBuilder(
stream: listStream
...
}
_fetchMore() {
...
// Do your fetch and then just add items to the stream
_list.addAll(snapList);
_listController.sink.add(_list);
...
}
final_list=list();
final _listController=StreamController.broadcast();
Stream get listStream=>\u listController.Stream;
@凌驾
void initState(){
super.initState();
//在这里,您需要加载您的第一页,然后添加到您的流
...
_list.addAll(firstPageItems);
_listController.sink.add(_list);
}
@凌驾
无效处置(){
super.dispose();
}
小部件buildListMessage(){
回程灵活(
孩子:StreamBuilder(
流:listStream
...
}
_fetchMore(){
...
//进行提取,然后只向流中添加项目
_list.addAll(快照列表);
_listController.sink.add(_list);
...
}
试试这个实时列表分页
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();
}
类FireStoreRepository{
最终收集参考\u chatCollectionReference=
Firestore.instance.collection('Chat');
最终流量控制器\u chatController=
StreamController.broadcast();
List _allPagedResults=List();
静态常数int chatLimit=10;
DocumentSnapshot\u lastDocument;
bool_hasMoreData=true;
Stream listentochatsrelatime(){
_requestChats();
return\u chatController.stream;
}
void _requestChats(){
var pagechatQuery=\u chatCollectionReference
.orderBy('timestamp',降序:true)
.限额(查特限额);
如果(_lastDocument!=null){
pagechatQuery=
pagechatQuery.startAfterDocument(\u lastDocument);
}
如果(!\u hasMoreData)返回;
var currentRequestIndex=_allPagedResults.length;
pagechatQuery.snapshots()。侦听(
(快照){
if(snapshot.documents.isNotEmpty){
var generalChats=snapshot.documents
.map((快照)=>ChatModel.fromMap(快照.data))
.toList();
var pageExists=currentRequestIndex<_allPagedResults.length;
如果(页面存在){
_allPagedResults[currentRequestIndex]=通用帽;
}否则{
_allPagedResults.add(通用帽);
}
var allChats=\u allPagedResults.fold(
列表(),
(initialValue,pageItems)=>initialValue..addAll(pageItems));
_添加(所有聊天记录);
如果(currentRequestIndex==\u 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();
}
}
}
class ChatView扩展了StatefulWidget{
ChatView({Key}):超级(Key:Key);
@凌驾
_ChatViewState createState()=>\u ChatViewState();
}
类_ChatViewState扩展状态{
FireStoreRepository\u FireStoreRepository;
final ScrollController_listScrollController=新ScrollController();
@凌驾
void initState(){
super.initState();
_fireStoreRepository=fireStoreRepository();
_listScrollController.addListener(\u scrollListener);
}
@凌驾
小部件构建(构建上下文){
返回脚手架(
身体:灵活(
孩子:StreamBuilder(
流:\ u fireStoreRepository.ListenToChatsRelatime(),
生成器:(上下文,快照){
返回ListView.builder(
itemCount:snapshot.data.length,
控制器:\ u listScrollController,
收缩膜:对,
相反:是的,
itemBuilder:(上下文,索引){
...
}
);
}
)
),
);
}
void_scrollListener(){
如果(_listScrollController.offset>=
_listScrollController.position.maxScrollExtent&&
!\u listScrollController.position.outOfRange){
_fireStoreRepository.requestMoreData();
}
}
}
聊天室模型类
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),
);
}
}
类模型{
最终字符串用户标识;
最终字符串消息;
最终日期时间戳;
ChatModel({this.userID,this.message,this.timeStamp});
//发送
映射toMap(){
返回{
“userid”:userid,
“消息”:消息,
“时间戳”:时间戳,
};
}
//取回
静态ChatModel fromMap(mapm
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),
);
}
}