Flutter切换用户后DataService未刷新数据需热重启问题咨询
问题根因
当前实现仅在DataService.init()执行时拉取一次当前登录用户的习惯数据,没有监听Firebase Auth的登录态变化事件,切换账号后不会触发数据重载,必须重启应用才能生效。不需要额外嵌套FutureBuilder,核心是给Auth状态增加监听,在用户切换时主动刷新习惯数据流即可。
实现步骤
- 为DataService增加Firebase Auth状态订阅,用户登录、登出、切换账号时自动触发对应数据加载
- 补全StreamData类的数据更新方法,支持主动向流推送新的习惯数据
- 调整初始化逻辑,避免硬编码只加载一次数据,同时增加资源释放方法防止内存泄漏
修改后的data_service.dart代码
import 'dart:async'; import 'package:firebase_auth/firebase_auth.dart'; class DataService { late final Database db; Users? _user; late final StreamData<Map<int, Habit>> habits; // 新增Auth状态订阅对象,用于后续取消订阅 StreamSubscription<User?>? _authStateSub; Future<void> init() async { db = await HabitsDb.connectToDb(); habits = StreamData(initialValue: const {}, broadcast: true); // 监听登录态变化,用户切换/登录/登出时自动重载数据 _authStateSub = FirebaseAuth.instance.authStateChanges().listen((user) async { if (user == null) { // 登出状态:清空当前用户缓存和习惯数据 _user = null; habits.add(const {}); return; } // 新用户登录/账号切换:重新拉取对应用户数据 await _refreshHabitsForCurrentUser(); }); } // 刷新当前登录用户的习惯数据 Future<void> _refreshHabitsForCurrentUser() async { final currentUser = await getOrCreateUser(email: userEmail); _user = currentUser; final allHabits = await _getAllHabitsFromDb(); final filteredMap = <int, Habit>{}; for (final habit in allHabits) { if (habit.userId == currentUser.id) { filteredMap[habit.id] = habit; } } // 将新数据推送到流,所有监听页面自动更新 habits.add(filteredMap); } String get userEmail => AuthService.firebase().currentUser!.email; Future<List<Habit>> _getAllHabitsFromDb() async { final habitsMap = await HabitsDb.getAllHabits(db); return habitsMap.map((e) => Habit.fromDb(e)).toList(); } Future<Users> getOrCreateUser({ required String email, bool setAsCurrentUser = true, }) async { try { final user = await getUser(email: email); if (setAsCurrentUser) { _user = user; } return user; } on CouldNotFindUser { final createdUser = await createUser(email: email); if (setAsCurrentUser) { _user = createdUser; } return createdUser; } catch (e) { rethrow; } } // 释放资源,应用退出时调用 void dispose() { _authStateSub?.cancel(); habits.close(); } }
补全后的StreamData类代码
原有类缺少数据推送和流关闭方法,补充后即可支持动态更新数据:
class StreamData<T> { List<Habit> _notes = []; User? _user; late final StreamController<T> _controller; Stream<T> get stream => _controller.stream; late T _value; T get value => _value; StreamData({required T initialValue, bool broadcast = true}) { _controller = broadcast ? StreamController<T>.broadcast() : StreamController<T>(); _value = initialValue; _controller.add(_value); } // 更新数据并通知所有监听者 void add(T newValue) { _value = newValue; _controller.add(newValue); } // 关闭流释放资源 void close() { _controller.close(); } }
main.dart调整说明
原有初始化逻辑不需要大改,首次启动时Auth监听器会自动触发首次数据加载,不需要手动提前拉取习惯数据,页面层直接监听流即可自动响应变化:
void main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(); final dataService = DataService(); await dataService.init(); GetIt.I.registerSingleton(dataService); runApp(const MyApp()); }
使用说明
- 页面层直接使用
StreamBuilder监听dataService.habits.stream即可,切换账号时数据会自动刷新,不需要Hot Restart - 登出触发后数据流会自动清空,不会残留上一个用户的习惯数据
- 该实现同时解决了初始化时Firebase Auth未就绪导致的
currentUser空指针问题
内容的提问来源于stack exchange,提问作者Sol
相关产品推荐
相关产品推荐

