firebase 在聊天中检索数据时的进度指示器 - Flutter

Posted

技术标签:

【中文标题】firebase 在聊天中检索数据时的进度指示器 - Flutter【英文标题】:Progress Indicator when firebase is retrieving data on chat - Flutter 【发布时间】:2022-01-09 15:44:23 【问题描述】:

我有一个与 firebase 实时数据库聊天的颤振项目,当我打开与用户的聊天时,firebase 需要 1-3 秒来加载对话。

所以,我必须在 firebase 检索打开的聊天数据时插入进度指示器。

这是课程:

class ChatView extends StatefulWidget 
  const ChatView(
    Key key,
    @required this.itemId,
    @required this.chatFlag,
    @required this.buyerUserId,
    @required this.sellerUserId,

  ) : super(key: key);

  final String itemId;
  final String chatFlag;
  final String buyerUserId;
  final String sellerUserId;
  // final String isOffer;
  @override
  _ChatViewState createState() => _ChatViewState();


enum ChatUserStatus  active, in_active, offline 

class _ChatViewState extends State<ChatView>
    with SingleTickerProviderStateMixin, WidgetsBindingObserver 
  AnimationController animationController;
  DatabaseReference _messagesRef;
  DatabaseReference _chatRef;
  DatabaseReference _userPresence;
  final bool _anchorToBottom = true;
  FirebaseApp firebaseApp;
  PsValueHolder psValueHolder;
  String sessionId;
  ChatHistoryRepository chatHistoryRepository;
  NotificationRepository notiRepo;
  UserUnreadMessageRepository userUnreadMessageRepository;
  GalleryRepository galleryRepo;
  ProductRepository productRepo;
  GetChatHistoryProvider getChatHistoryProvider;
  UserUnreadMessageProvider userUnreadMessageProvider;
  ChatHistoryListProvider chatHistoryListProvider;
  ItemDetailProvider itemDetailProvider;
  GalleryProvider galleryProvider;
  NotificationProvider notiProvider;
  SyncChatHistoryParameterHolder holder;
  GetChatHistoryParameterHolder getChatHistoryParameterHolder;
  PsResource<ChatHistory> chatHistory;
  String lastTimeStamp;
  int lastAddedDateTimeStamp;
  String status = '';
  String itemId;
  String receiverId;
  String senderId;
  String otherUserId;

  ChatUserStatus isActive;

  TextEditingController messageController = TextEditingController();

  Future<FirebaseApp> configureDatabase() async 
    WidgetsFlutterBinding.ensureInitialized();
    final FirebaseApp app = await Firebase.initializeApp(

      options: Platform.isios
          ? const FirebaseOptions(
              appId: Config.iosGoogleAppId,
              messagingSenderId: Config.iosGcmSenderId,
              databaseURL: Config.iosDatabaseUrl,
              projectId: Config.iosProjectId,
              apiKey: Config.iosApiKey)
          : const FirebaseOptions(
              appId: Config.androidGoogleAppId,
              apiKey: Config.androidApiKey,
              projectId: Config.androidProjectId,
              messagingSenderId: Config.androidGcmSenderId,
              databaseURL: Config.androidDatabaseUrl,
            ),
    );

    return app;
  

  @override
  void initState() 
    super.initState();
    configureDatabase().then((FirebaseApp app) 
      firebaseApp = app;
    );

    final FirebaseDatabase database = FirebaseDatabase(app: firebaseApp);
    _messagesRef = database.reference().child('Message');
    _chatRef = database.reference().child('Current_Chat_With');
    _userPresence = database.reference().child('User_Presence');

    if (database != null && database.databaseURL != null) 
      database.setPersistenceEnabled(true);
      database.setPersistenceCacheSizeBytes(10000000);
    
    animationController =
        AnimationController(duration: PsConfig.animation_duration, vsync: this);
    WidgetsBinding.instance.addObserver(this);
  

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) 
    if (state == AppLifecycleState.resumed) 
      // user returned to our app
     else if (state == AppLifecycleState.inactive) 
      _chatRef.child(psValueHolder.loginUserId).remove();
      // app is inactive
     else if (state == AppLifecycleState.paused) 
      _chatRef.child(psValueHolder.loginUserId).remove();

      // user is about quit our app temporally
     else if (state == AppLifecycleState.detached) 
      // app suspended (not used in iOS)
    
  

  @override
  void dispose() 
    super.dispose();

    if (mounted) 
      _chatRef.child(psValueHolder.loginUserId).remove();
      _userPresence.child(psValueHolder.loginUserId).remove();
    

    WidgetsBinding.instance.removeObserver(this);
    Utils.isReachChatView = false;
  

  Future<bool> resetUnreadMessageCount(
      ChatHistoryListProvider chatHistoryListProvider,
      PsValueHolder valueHolder,
      UserUnreadMessageProvider userUnreadMessageProvider) async 
    final ResetUnreadMessageParameterHolder resetUnreadMessageParameterHolder =
        ResetUnreadMessageParameterHolder(
            itemId: widget.itemId,
            buyerUserId: widget.buyerUserId,
            sellerUserId: widget.sellerUserId,
            type: widget.chatFlag == PsConst.CHAT_FROM_BUYER
                ? PsConst.CHAT_TO_SELLER
                : PsConst.CHAT_TO_BUYER);

    final dynamic _returnData = await chatHistoryListProvider
        .resetUnreadMessageCount(resetUnreadMessageParameterHolder.toMap());

    if (_returnData == null) 

      if (valueHolder.loginUserId != null && valueHolder.loginUserId != '') 
        final UserUnreadMessageParameterHolder userUnreadMessageHolder =
            UserUnreadMessageParameterHolder(
                userId: valueHolder.loginUserId,
                deviceToken: valueHolder.deviceToken);
        userUnreadMessageProvider
            .userUnreadMessageCount(userUnreadMessageHolder);
      
      return true;
     else 
      return false;
    
  

  Future<void> _insertDataToFireBase(
    String id,
    bool isSold,
    bool isUserBought,
    String itemId,
    String message,
    int offerStatus,
    String sendByUserId,
    String sessionId,
    int type,
  ) async 
    final Message messages = Message();
    messages.addedDate = Utils.getTimeStamp();
    messages.id = id;
    messages.isSold = isSold;
    messages.isUserBought = isUserBought;
    messages.itemId = itemId;
    messages.message = message;
    messages.offerStatus = offerStatus;
    messages.sendByUserId = sendByUserId;
    messages.sessionId = sessionId;
    messages.type = type;

    final String newkey = _messagesRef.child(sessionId).push().key;
    messages.id = newkey;

    _messagesRef
        .child(sessionId)
        .child(newkey)
        .set(messages.toInsertMap(messages));

  

  Future<void> _deleteDataToFireBase(
    String id,
    bool isSold,
    String itemId,
    String message,
    String sendByUserId,
    String sessionId,
  ) async 
    final Message messages = Message();
    messages.addedDate = Utils.getTimeStamp();
    messages.id = id;
    messages.isSold = isSold;
    messages.itemId = itemId;
    messages.message = message;
    messages.sendByUserId = sendByUserId;
    messages.sessionId = sessionId;

    final String key =
        _messagesRef.child(sessionId).child(id).remove().toString();
    messages.id = key;

    _messagesRef
        .child(sessionId)
        .child(key)
        .set(messages.toDeleteMap(messages));
  

  Future<void> _updateDataToFireBase(
    int addedDate,
    String id,
    bool isSold,
    bool isUserBought,
    String itemId,
    String message,
    int offerStatus,
    String sendByUserId,
    String sessionId,
    int type,
  ) async 
    final Message messages = Message();
    messages.id = id;
    messages.isSold = isSold;
    messages.isUserBought = isUserBought;
    messages.itemId = itemId;
    messages.message = message;
    messages.offerStatus = offerStatus;
    messages.sendByUserId = sendByUserId;
    messages.sessionId = sessionId;
    messages.type = type;
    messages.addedDateTimeStamp = addedDate;

    _messagesRef
        .child(sessionId)
        .child(messages.id)
        .set(messages.toUpdateMap(messages));
  

  Future<void> _insertSenderAndReceiverToFireBase(
      String sessionId,
      String itemId,
      String receiverId,
      String senderId,
      String userName) async 
    final Chat chat =
        Chat(itemId: itemId, receiverId: receiverId, senderId: senderId);

    _chatRef.child(senderId).set(chat.toMap(chat));

    final ChatUserPresence chatUserPresence =
        ChatUserPresence(userId: senderId, userName: userName);

    _userPresence.child(senderId).set(chatUserPresence.toMap(chatUserPresence));
  

  @override
  Widget build(BuildContext context) 
    const Widget _spacingWidget = SizedBox(
      width: PsDimens.space10,
    );
    lastTimeStamp = null;

    psValueHolder = Provider.of<PsValueHolder>(context);
    chatHistoryRepository = Provider.of<ChatHistoryRepository>(context);
    notiRepo = Provider.of<NotificationRepository>(context);
    galleryRepo = Provider.of<GalleryRepository>(context);
    productRepo = Provider.of<ProductRepository>(context);
    userUnreadMessageRepository =
        Provider.of<UserUnreadMessageRepository>(context);
    if (psValueHolder.loginUserId != null) 
      if (psValueHolder.loginUserId == widget.buyerUserId) 
        sessionId =
            Utils.sortingUserId(widget.sellerUserId, widget.buyerUserId);
        otherUserId = widget.sellerUserId;
       else if (psValueHolder.loginUserId == widget.sellerUserId) 
        sessionId =
            Utils.sortingUserId(widget.buyerUserId, widget.sellerUserId);
        otherUserId = widget.buyerUserId;
      

      _insertSenderAndReceiverToFireBase(sessionId, widget.itemId, otherUserId,
          psValueHolder.loginUserId, psValueHolder.loginUserName);
    

    _chatRef.child(otherUserId).onValue.listen((Event event) 
      if (event.snapshot.value == null) 
        if (isActive == null || isActive != ChatUserStatus.offline && mounted) 
          setState(() 
            status = Utils.getString(context, 'chat_view__status_offline');
            isActive = ChatUserStatus.offline;
          );
        
       else 
        itemId = event.snapshot.value['itemId'];
        final String _receiverId = event.snapshot.value['receiver_id'];

        if (_receiverId == psValueHolder.loginUserId &&
            itemId == widget.itemId) 
          if (isActive != ChatUserStatus.active && mounted) 
            setState(() 
              status = Utils.getString(context, 'chat_view__status_active');
              isActive = ChatUserStatus.active;
            );
          
         else 
          if (isActive != ChatUserStatus.in_active && mounted) 
            setState(() 
              status = Utils.getString(context, 'chat_view__status_inactive');
              isActive = ChatUserStatus.in_active;
            );
          
        
      
    );

    Future<void> checkOfferStatus(ChatHistory chatHistory) async 
      if (chatHistory != null &&
          chatHistory.isOffer == PsConst.ONE &&
          chatHistory.isAccept != PsConst.ONE) 
        await getChatHistoryProvider
            .getChatHistory(getChatHistoryParameterHolder);
      
    

    return Scaffold(
      appBar: PreferredSize(
        preferredSize: const Size.fromHeight(0), // here the desired height
        child: AppBar(
          automaticallyImplyLeading: true,
          systemOverlayStyle:  SystemUiOverlayStyle(
            statusBarIconBrightness: Utils.getBrightnessForAppBar(context),
          ),
          iconTheme: Theme.of(context)
              .iconTheme
              .copyWith(color: PsColors.textPrimaryColor),
          title: Text(
            status,
            textAlign: TextAlign.center,
            style: Theme.of(context).textTheme.headline6.copyWith(
                fontWeight: FontWeight.bold,
                color: PsColors.white),
          ),
        backgroundColor: PsColors.mainColor,
        bottomOpacity: 0.0,
        elevation: 0.0)),
      body: PsWidgetWithMultiProvider(
          child: MultiProvider(
              providers: <SingleChildWidget>[
            ChangeNotifierProvider<ItemDetailProvider>(
                lazy: false,
                create: (BuildContext context) 
                  itemDetailProvider = ItemDetailProvider(
                      repo: productRepo, psValueHolder: psValueHolder);

                  final String loginUserId =
                      Utils.checkUserLoginId(psValueHolder);
                  itemDetailProvider.loadProduct(widget.itemId, loginUserId);

                  return itemDetailProvider;
                ),
            ChangeNotifierProvider<UserUnreadMessageProvider>(
                lazy: false,
                create: (BuildContext context) 
                  userUnreadMessageProvider = UserUnreadMessageProvider(
                      repo: userUnreadMessageRepository);
                  return userUnreadMessageProvider;
                ),
            ChangeNotifierProvider<ChatHistoryListProvider>(
                lazy: false,
                create: (BuildContext context) 
                  chatHistoryListProvider =
                      ChatHistoryListProvider(repo: chatHistoryRepository);

                  resetUnreadMessageCount(chatHistoryListProvider,
                      psValueHolder, userUnreadMessageProvider);
                  return chatHistoryListProvider;
                ),
            ChangeNotifierProvider<NotificationProvider>(
                lazy: false,
                create: (BuildContext context) 
                  notiProvider = NotificationProvider(
                      repo: notiRepo, psValueHolder: psValueHolder);

                  return notiProvider;
                ),
            ChangeNotifierProvider<GalleryProvider>(
                lazy: false,
                create: (BuildContext context) 
                  galleryProvider = GalleryProvider(
                    repo: galleryRepo,
                  );

                  return galleryProvider;
                ),
            ChangeNotifierProvider<GetChatHistoryProvider>(
                lazy: false,
                create: (BuildContext context) 
                  getChatHistoryProvider =
                      GetChatHistoryProvider(repo: chatHistoryRepository);
                  getChatHistoryParameterHolder = GetChatHistoryParameterHolder(
                      itemId: widget.itemId,
                      buyerUserId: widget.buyerUserId,
                      sellerUserId: widget.sellerUserId);
                  getChatHistoryProvider
                      .getChatHistory(getChatHistoryParameterHolder);

                  return getChatHistoryProvider;
                ),
          ],
              child: Consumer<ItemDetailProvider>(builder:
                  (BuildContext context, ItemDetailProvider itemDetailProvider,
                      Widget child) 
                if (itemDetailProvider.itemDetail != null &&
                    itemDetailProvider.itemDetail.data != null) 
                  return Container(
                    color: Utils.isLightMode(context)
                        ? Colors.grey[100]
                        : Colors.grey[900],
                    child: Column(
                      children: <Widget>[
                        Align(
                            alignment: Alignment.topCenter,
                            child: Container(
                              alignment: Alignment.topCenter,
                              width: double.infinity,
                              child: ItemInfoWidget(
                                insertDataToFireBase: _insertDataToFireBase,
                                sessionId: sessionId,
                                itemData: itemDetailProvider.itemDetail.data,
                                sendByUserId: psValueHolder.loginUserId ?? '',
                                chatFlag: widget.chatFlag,
                                buyerUserId: widget.buyerUserId,
                                sellerUserId: widget.sellerUserId,
                                chatHistoryProvider: getChatHistoryProvider,
                                isOffer:
                                    (getChatHistoryProvider.chatHistory.data !=
                                                null &&
                                            getChatHistoryProvider
                                                    .chatHistory.data.id !=
                                                '')
                                        ? getChatHistoryProvider
                                            .chatHistory.data.isOffer
                                        : '0',
                                isUserOnline: isActive == ChatUserStatus.active
                                    ? PsConst.ONE
                                    : PsConst.ZERO,
                              )
                            )),
                        Flexible(
                          child: Container(
                            margin:
                                const EdgeInsets.only(bottom: PsDimens.space12),
                            child: FirebaseAnimatedList(
                              key: ValueKey<bool>(_anchorToBottom),
                              query: _messagesRef
                                  .child(sessionId)
                                  .orderByChild('itemId')
                                  .equalTo(widget.itemId),
                              reverse: _anchorToBottom,
                              sort: _anchorToBottom
                                  ? (DataSnapshot a, DataSnapshot b) 
                                      return b.value['addedDate']
                                          .toString()
                                          .compareTo(
                                              a.value['addedDate'].toString());
                                    
                                  : null,
                              itemBuilder: (BuildContext context,
                                  DataSnapshot snapshot,
                                  Animation<double> animation,
                                  int index) 
                                print('- - - - - - -  /nIndex : $index');
                                bool isSameDate = false;
                                final Message messages =
                                    Message().fromMap(snapshot.value);

                                final String chatDateString =
                                    Utils.convertTimeStampToDate(
                                        messages.addedDateTimeStamp);
                                if (index == 0 || lastTimeStamp == null) 
                                  lastTimeStamp = chatDateString;
                                  lastAddedDateTimeStamp =
                                      messages.addedDateTimeStamp;
                                

                                final DateTime msgDate =
                                Utils.getDateOnlyFromTimeStamp(
                                    messages.addedDateTimeStamp);

                                final DateTime lastDate =
                                Utils.getDateOnlyFromTimeStamp(
                                    lastAddedDateTimeStamp);


                                if (lastTimeStamp == chatDateString ||
                                    msgDate.compareTo(lastDate) >= 0) 
                                  isSameDate = true;
                                 else 
                                  isSameDate = false;
                                

                                final Widget _chatCell =
                                _ChatPageWidget(
                                  buyerUserId: widget.buyerUserId,
                                  sellerUserId: widget.sellerUserId,
                                  chatFlag: widget.chatFlag,
                                  chatHistoryProvider: getChatHistoryProvider,
                                  chatHistoryParameterHolder:
                                      getChatHistoryParameterHolder,
                                  messageObj: messages,
                                  itemDetail:
                                      itemDetailProvider.itemDetail.data,
                                  psValueHolder: psValueHolder,
                                  updateDataToFireBase: _updateDataToFireBase,
                                  insertDataToFireBase: _insertDataToFireBase,
                                  deleteDataToFireBase: _deleteDataToFireBase,
                                  checkOfferStatus: checkOfferStatus,
                                  index: index,
                                  isUserOnline:
                                  isActive == ChatUserStatus.active
                                      ? PsConst.ONE
                                      : PsConst.ZERO,
                                );

                                Widget _dateWidget;
                                if (!isSameDate) 
                                  _dateWidget = Container(
                                    margin: const EdgeInsets.only(
                                        top: PsDimens.space8,
                                        bottom: PsDimens.space8),
                                    child: Row(
                                      mainAxisAlignment:
                                          MainAxisAlignment.spaceBetween,
                                      children: <Widget>[
                                        _spacingWidget,
                                        const Expanded(
                                          child: Divider(
                                              height: PsDimens.space1,
                                              color: Colors.black54),
                                        ),
                                        _spacingWidget,
                                        Container(
                                          padding: const EdgeInsets.all(
                                              PsDimens.space4),
                                          decoration: BoxDecoration(
                                              color: Colors.black54,
                                              borderRadius:
                                                  BorderRadius.circular(
                                                      PsDimens.space8)),
                                          child: Text(
                                            lastTimeStamp,
                                            style: Theme.of(context)
                                                .textTheme
                                                .caption
                                                .copyWith(color: Colors.white),
                                          ),
                                        ),
                                        _spacingWidget,
                                        const Expanded(
                                          child: Divider(
                                              height: PsDimens.space1,
                                              color: Colors.black54),
                                        ),
                                        _spacingWidget,
                                      ],
                                    ),
                                  );

                                  lastTimeStamp = chatDateString;
                                  lastAddedDateTimeStamp =
                                      messages.addedDateTimeStamp;
                                

                                if (msgDate.compareTo(lastDate) >= 0) 
                                  lastTimeStamp = chatDateString;
                                  lastAddedDateTimeStamp =
                                      messages.addedDateTimeStamp;
                                

                                return isSameDate
                                    ? _chatCell
                                    : Column(
                                        mainAxisSize: MainAxisSize.min,
                                        children: <Widget>[
                                          _chatCell,
                                          _dateWidget,
                                        ],
                                      );
                              ,
                            ),
                          ),
                        ),
                      ],
                    ),
                  );
                 else 
                  return Container();
                
              ))),
    );
  

你能建议我一个解决方案吗?

Flutter 2.5.3 版

【问题讨论】:

在处理 Futures 时,使用 FutureBuilder 小部件。 【参考方案1】:

像这样实现FutureBuilder(最好在初始化 Firebase 的 main.dart 中):

return FutureBuilder(
          // Initialize FlutterFire:
          future: _initialization,
      builder: (context, snapshot) 
        // Check for errors
        if (snapshot.hasError) 
          return SomethingWentWrong();
        

        // Once complete, show your application
        if (snapshot.connectionState == ConnectionState.done) 
          return MyAwesomeApp();
        

        // Otherwise, show something whilst waiting for initialization to complete
        return Loading();
      ,
    );

对于Loading();,您可以制作自己的自定义小部件或仅渲染CircularProgressIndicator()。 Here你可以了解如何配置它。

【讨论】:

你能用我的代码 sn-p 做例子吗?对不起我的新手问题 您的 sn-p 相当大,我不确定您的整体项目结构如何,我建议您深入了解 this article 并将其应用于您的项目,因为您知道最好的,这将是您成长为开发人员的一种更好的做法;)

以上是关于firebase 在聊天中检索数据时的进度指示器 - Flutter的主要内容,如果未能解决你的问题,请参考以下文章

将数据从 FireBase 检索到颤振项目时出错

Firebase 聊天用户正在输入指示单元格

使用flutter firebase在线/离线的用户存在

输入聊天消息时的Firebase警告[重复]

从 Firebase 检索和读取数据作为 NSArray (Swift 3)

用于 firebase_storage 的 Flutter OnProgressListener?