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

同一设备切换登录后新用户显示旧用户数据的Flutter技术问题

问题诊断与解决方案

问题根源

你的核心问题在于**UserModel和DatabaseService是全局单例实例**,应用启动时就完成初始化,不会随用户登录状态切换而重建或刷新数据。用户B登录后,这两个实例仍持有用户A的数据,重启应用才会重新初始化实例,所以能正常显示。

之前尝试的删除缓存、给MultiProvider加UniqueKey无效,是因为前者针对本地存储,后者无法触发Provider实例的重建——MultiProvider的Key仅影响自身Widget的重建,不会重新调用create方法生成新的服务实例。


修复方案

1. 修正AuthService的类型安全

先明确user流的类型,避免后续使用时的类型模糊:

class AuthService {
  final FirebaseAuth _auth = FirebaseAuth.instance;
  
  // 明确为Stream<User?>类型
  Stream<User?> get user => _auth.userChanges();
    
  Future<void> signIn(String email, String password) async {
    await _auth.signInWithEmailAndPassword(email: email, password: password);
  }
  
  Future<void> signOut() async {
    await _auth.signOut();
  }
}

2. 让服务/模型依赖当前用户

使用ProxyProvider系列组件,将用户身份作为依赖,当用户切换时自动重建或刷新UserModel和DatabaseService:

runApp(
  MultiProvider(
    providers: [
      Provider<AuthService>(
        create: (_) => AuthService(),
      ),
      // 监听AuthService的用户流,作为后续Provider的依赖
      StreamProxyProvider<AuthService, User?>(
        update: (context, auth, _) => auth.user,
      ),
      // 用户变化时重建UserModel并加载新数据
      ChangeNotifierProxyProvider<User?, UserModel>(
        create: (context) => UserModel(),
        update: (context, currentUser, oldModel) {
          final newModel = UserModel();
          if (currentUser != null) {
            newModel.loadUserData(currentUser.uid);
          } else {
            newModel.clearUserData();
          }
          return newModel;
        },
      ),
      // 用户变化时生成对应uid的DatabaseService实例
      ProxyProvider<User?, DatabaseService>(
        update: (context, currentUser, _) => DatabaseService(uid: currentUser?.uid),
      ),
    ],
    child: const MyApp(),
  ),
);

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      home: StreamBuilder<User?>(
        stream: Provider.of<AuthService>(context, listen: false).user,
        builder: (context, snapshot) {
          if (snapshot.hasError) {
            print("错误:${snapshot.error}");
            return const Scaffold(body: Center(child: Text("登录出错")));
          }
          // 等待用户流加载状态
          if (snapshot.connectionState == ConnectionState.waiting) {
            return const Scaffold(body: Center(child: CircularProgressIndicator()));
          }
          return snapshot.hasData ? const Home() : const SignUp();
        },
      ),
    );
  }
}

3. 更新UserModel的逻辑

添加加载/清空用户数据的方法,确保用户切换时数据同步:

class UserModel extends ChangeNotifier {
  String? userName;
  // 其他用户数据字段

  // 加载指定用户的数据
  void loadUserData(String uid) async {
    // 调用DatabaseService获取当前用户数据
    final db = DatabaseService(uid: uid);
    final userData = await db.getUserData();
    userName = userData['name'];
    // 其他字段赋值...
    notifyListeners();
  }

  // 用户退出时清空数据
  void clearUserData() {
    userName = null;
    // 其他字段清空...
    notifyListeners();
  }
}

4. 修改DatabaseService依赖用户UID

让服务实例绑定当前用户的UID,确保每次操作都针对正确的用户:

class DatabaseService {
  final String? uid;

  DatabaseService({this.uid});

  // 根据uid获取用户数据的示例方法
  Future<Map<String, dynamic>> getUserData() async {
    if (uid == null) return {};
    // 这里替换为你的数据库查询逻辑,比如Firestore
    // final doc = await FirebaseFirestore.instance.collection('users').doc(uid).get();
    // return doc.data() ?? {};
    return {};
  }
}

关键要点

  • 所有与用户身份绑定的服务/模型,必须随用户登录状态变化而更新,不能用全局静态实例
  • 利用Provider的Proxy系列组件,自动处理依赖关系的更新,无需手动管理
  • 用户退出时,主动清空模型数据并调用notifyListeners()触发UI刷新

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 15:10:18