Flutter技术问题:如何向已有Stream中添加事件?
首先明确:你无法直接访问FirebaseAuth.instance.idTokenChanges()返回的Stream对应的控制器,这个流是Firebase SDK内部管理的,没有暴露sink接口供外部手动添加事件。不过有几种可行的方案实现你要的效果:
方案1:强制刷新ID Token触发流更新
当你更新displayName后,FirebaseAuth的currentUser对象其实已经更新了,但idTokenChanges()只会在ID Token本身变化时才会发出新事件。这时候可以强制刷新ID Token,让流主动推送最新的用户数据:
// 更新displayName后调用此方法 Future<void> refreshUserToken() async { final user = FirebaseAuth.instance.currentUser; if (user != null) { // 传入true强制刷新token await user.getIdToken(true); } }
调用这个方法后,idTokenChanges()会因为token刷新而发出包含最新用户信息的事件,StreamBuilder就会自动重建UI展示新的displayName。
方案2:自定义合并流
创建一个自定义的Stream,将Firebase原生的idTokenChanges()和你自己的手动更新流合并,这样既能监听登录/退出事件,又能手动触发用户信息更新:
// 定义一个全局或在Provider中维护的BehaviorSubject final userUpdateSubject = BehaviorSubject<User?>(); // 合并两个流 Stream<User?> get combinedUserStream => Stream.merge([ FirebaseAuth.instance.idTokenChanges(), userUpdateSubject.stream, ]); // 更新displayName后手动推送事件 Future<void> updateDisplayNameAndNotify(String newName) async { final user = FirebaseAuth.instance.currentUser; if (user != null) { await user.updateDisplayName(newName); // 手动将更新后的用户对象推送到自定义流 userUpdateSubject.add(user); } }
然后将combinedUserStream作为StreamProvider的数据源,这样每次手动调用updateDisplayNameAndNotify时,合并流就会发出新事件,触发UI重建。
方案3:使用ChangeNotifierProvider替代StreamProvider
如果需要更灵活的状态管理,改用ChangeNotifier来维护用户状态,手动控制更新通知:
class UserProvider extends ChangeNotifier { User? _user; User? get user => _user; UserProvider() { // 监听Firebase的登录状态变化 FirebaseAuth.instance.idTokenChanges().listen((user) { _user = user; notifyListeners(); }); } // 更新displayName并通知UI Future<void> updateDisplayName(String newName) async { if (_user != null) { await _user!.updateDisplayName(newName); // 更新本地状态并通知 _user = FirebaseAuth.instance.currentUser; notifyListeners(); } } }
在Widget树中用ChangeNotifierProvider提供这个实例,然后在需要的地方通过Consumer<UserProvider>获取用户状态,调用updateDisplayName后,UI会自动重建展示新的名称。
内容的提问来源于stack exchange,提问作者Cedric

