You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Firestore流函数返回的Stream数据关联到Flutter Bloc并整合仓库?

将Firestore Stream关联到Flutter Bloc并整合FirebaseChatApi仓库

下面一步步实现Firestore流与Flutter Bloc的关联,同时整合你提供的FirebaseChatApi仓库:

1. 定义Bloc的事件和状态

首先明确Bloc需要处理的事件和对应的状态:

事件类

abstract class ChatContactsEvent {}

// 触发获取聊天联系人列表的事件
class FetchChatContacts extends ChatContactsEvent {}

状态类

abstract class ChatContactsState {}

// 加载中状态
class ChatContactsLoading extends ChatContactsState {}

// 加载成功状态,携带联系人数据
class ChatContactsLoaded extends ChatContactsState {
  final List<ChatContactModel> contacts;

  ChatContactsLoaded(this.contacts);
}

// 加载失败状态,携带错误信息
class ChatContactsLoadFailed extends ChatContactsState {
  final String error;

  ChatContactsLoadFailed(this.error);
}

2. 实现Bloc并关联Firestore Stream

在Bloc中注入FirebaseChatApi,通过监听它返回的Stream来更新状态:

class ChatContactsBloc extends Bloc<ChatContactsEvent, ChatContactsState> {
  final FirebaseChatApi _firebaseChatApi;
  StreamSubscription? _contactsSubscription;

  ChatContactsBloc(this._firebaseChatApi) : super(ChatContactsLoading()) {
    // 处理FetchChatContacts事件
    on<FetchChatContacts>((event, emit) {
      emit(ChatContactsLoading());
      // 先取消之前的订阅,避免重复监听
      _contactsSubscription?.cancel();
      // 监听Firestore返回的Stream
      _contactsSubscription = _firebaseChatApi.getChatContacts().listen(
        (contacts) {
          emit(ChatContactsLoaded(contacts));
        },
        onError: (error) {
          emit(ChatContactsLoadFailed(error.toString()));
        },
      );
    });

    // 可选:Bloc初始化时自动触发获取联系人事件
    add(FetchChatContacts());
  }

  @override
  Future<void> close() {
    // 关闭Bloc时取消Stream订阅,防止内存泄漏
    _contactsSubscription?.cancel();
    return super.close();
  }
}

3. 整合FirebaseChatApi到Bloc

你提供的FirebaseChatApi可以直接作为依赖传入Bloc,这里做一点小优化,把Firebase实例提到类成员,避免每次调用方法都重新创建:

class FirebaseChatApi {
  final FirebaseFirestore _firestore = FirebaseFirestore.instance;
  final FirebaseAuth _auth = FirebaseAuth.instance;

  Stream<List<ChatContactModel>> getChatContacts() {
    return _firestore
        .collection('users')
        .doc(_auth.currentUser!.uid)
        .collection('chats')
        .snapshots()
        .asyncMap((event) async {
      List<ChatContactModel> contacts = [];
      for (var document in event.docs) {
        var chatContact = ChatContactModel.fromJson(document.data());
        contacts.add(ChatContactModel(
          name: chatContact.name,
          profilePic: chatContact.profilePic,
          contactId: chatContact.contactId,
          timeSent: chatContact.timeSent,
          lastMessage: chatContact.lastMessage,
        ));
      }
      return contacts;
    });
  }
}

4. 在UI中使用Bloc

通过BlocBuilder监听状态变化,渲染对应的UI:

BlocBuilder<ChatContactsBloc, ChatContactsState>(
  builder: (context, state) {
    if (state is ChatContactsLoading) {
      return const Center(child: CircularProgressIndicator());
    } else if (state is ChatContactsLoaded) {
      return ListView.builder(
        itemCount: state.contacts.length,
        itemBuilder: (context, index) {
          final contact = state.contacts[index];
          return ListTile(
            leading: CircleAvatar(
              backgroundImage: NetworkImage(contact.profilePic),
            ),
            title: Text(contact.name),
            subtitle: Text(contact.lastMessage),
            trailing: Text(DateFormat.jm().format(contact.timeSent)),
          );
        },
      );
    } else if (state is ChatContactsLoadFailed) {
      return Center(child: Text('加载失败: ${state.error}'));
    }
    return const SizedBox();
  },
)

需要注意的地方

  • 务必在Bloc的close方法中取消Stream订阅,避免内存泄漏
  • 建议用依赖注入框架(比如get_it)来管理FirebaseChatApi实例,方便后续替换实现或做单元测试
  • 要处理_auth.currentUser为null的情况,比如添加空值判断,避免空指针崩溃

内容的提问来源于stack exchange,提问作者Janam Maharjan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 16:48:58