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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 19:27:26