Hive字段值不更新问题:登录后热重载仍跳转登录页
问题:Hive热重载后isLoggedIn值不更新导致页面跳转异常
我用Hive的users box存储用户数据,在main.dart里注册并打开适配器:
void main() async { await Hive.initFlutter(); Hive.registerAdapter(UserDBAdapter()); await Hive.openBox<UserDB>('users'); return runApp( MyApp(), ); }
在Bloc的登录函数中,登录成功后把user.isLoggedIn设为true,并调用save()持久化:
class UserBloc extends Bloc<UserEvent, UserState> { UserDB user = UserDB(); final usersBox = Hive.box<UserDB>('users'); UserRepository userRepository; UserBloc(this.userRepository) : super(UserInitial()) { createUser(); verifyUser(); loginUser(); logoutUser(); usersBox.put('user', user); } Future<void> loginUser() async { return on<LoginUser>((event, emit) async { emit(UserLoading()); await Future.delayed(const Duration(milliseconds: 500)); try { final result = await userRepository.login( event.email, event.password, ); if (result['success'] == false) { emit(UserError(result['message'])); } else { emit( UserLoggedIn(), ); user.isLoggedIn = true; // 此处设为true user.token = result['token']; user.save(); // 保存变更到本地存储 } } catch (error) { emit( UserError( error.toString(), ), ); } }); }
但热重载后应用会跳转到登录页而非HomeScreen,在页面的build方法中读取userDB.isLoggedIn打印为false:
@override void initState() { if (Hive.box<UserDB>('users').get('user') == null) { print('empty'); // 未打印,说明本地存储有用户数据 Hive.box<UserDB>('users').put( 'user', UserDB(isVerified: false, isLoggedIn: false), ); } super.initState(); } @override Widget build(BuildContext context) { final userDB = Hive.box<UserDB>('users').get('user')!; print(userDB.isLoggedIn); // 此处打印false而非true if (userDB.isLoggedIn) { return const NavigationScreen(); } else if (userDB.isVerified && !userDB.isLoggedIn) { return AnimatedSplashScreen( splash: const SplashScreen(), duration: 4000, nextScreen: const LoginSignUpSwitch(), ); } else { return AnimatedSplashScreen( splash: const SplashScreen(), duration: 4000, nextScreen: const WelcomeScreen(), ); } }
UserDB类定义:
import 'package:hive/hive.dart'; part 'user.g.dart'; @HiveType(typeId: 1) class UserDB extends HiveObject { UserDB({ this.name, this.email, this.isVerified = false, this.isLoggedIn = false, this.token, }); // NAME (0) @HiveField(0) String? name; //EMAIL(1) @HiveField(1) String? email; //IS-VERIFIED(2) @HiveField(2, defaultValue: false) bool isVerified; //IS-LOGGEDIN(3) @HiveField(3, defaultValue: false) bool isLoggedIn; //TOKEN(4) @HiveField(4) String? token; }
注意:在HomeScreen中打印userDB.isLoggedIn会输出true:
final userDB = Hive.box<UserDB>('users').get('user'); print(userDB!.isLoggedIn); // 此处打印true
原因分析
- Bloc初始化覆盖本地数据:
UserBloc构造函数中直接创建新的UserDB()实例,然后执行usersBox.put('user', user),热重载时Bloc重新初始化,会把本地存储中已有的登录状态覆盖成初始的isLoggedIn=false。 - 未读取本地已有数据:Bloc初始化时没有先从Hive读取已存在的
user数据,而是直接用新实例覆盖,导致登录后的状态在热重载时丢失。 - 页面未监听数据变化:当前页面
build方法仅初始化时读取一次Hive数据,即使数据更新也不会触发重新build,但核心问题还是Bloc的初始化逻辑错误。
解决方案
1. 修正Bloc初始化逻辑
修改UserBloc构造函数,先读取本地已有数据,不存在时再创建新实例,避免覆盖已有状态:
class UserBloc extends Bloc<UserEvent, UserState> { late UserDB user; final usersBox = Hive.box<UserDB>('users'); UserRepository userRepository; UserBloc(this.userRepository) : super(UserInitial()) { // 优先读取本地存储的用户数据,无数据时再创建新实例 user = usersBox.get('user') ?? UserDB(); createUser(); verifyUser(); loginUser(); logoutUser(); // 仅当本地无数据时才写入初始值 if (!usersBox.containsKey('user')) { usersBox.put('user', user); } } // 其他代码保持不变 }
2. 页面监听Hive数据变化(可选优化)
如果需要数据更新时页面自动刷新,使用ValueListenableBuilder监听box变化:
@override Widget build(BuildContext context) { return ValueListenableBuilder( valueListenable: Hive.box<UserDB>('users').listenable(), builder: (context, box, child) { final userDB = box.get('user')!; print(userDB.isLoggedIn); if (userDB.isLoggedIn) { return const NavigationScreen(); } else if (userDB.isVerified && !userDB.isLoggedIn) { return AnimatedSplashScreen( splash: const SplashScreen(), duration: 4000, nextScreen: const LoginSignUpSwitch(), ); } else { return AnimatedSplashScreen( splash: const SplashScreen(), duration: 4000, nextScreen: const WelcomeScreen(), ); } }, ); }
验证逻辑
修改后,热重载时Bloc会先读取本地已存储的user数据,不会再用新实例覆盖,isLoggedIn会保持登录后的true状态,页面就能正确跳转到NavigationScreen。而HomeScreen能读到正确值,是因为它没有在初始化时覆盖数据,直接读取了本地存储的最新值。
内容的提问来源于stack exchange,提问作者Samuel
相关产品推荐
相关产品推荐

