如何通过Provider获取变量更新值?登录重启后状态丢失问题
Flutter Provider认证状态持久化问题
问题描述
使用Flutter的Provider管理应用状态时,其他变量更新后能正常获取新值,但布尔变量_isAuthenticated存在异常:登录成功后退出应用再重新打开,仍然加载LoginPage,无法获取该变量的更新值。
相关代码
AuthProvider代码
class AuthProvider extends ChangeNotifier { bool _isAuthenticated = false; late AuthUseCase authUseCase; LoginResponse _userResponse = LoginResponse.empty(); UserAccountDto _userAccountDto = UserAccountDto.empty(); ForgotPasswordDto _forgotPasswordDto = ForgotPasswordDto(); ForgotPasswordDto get forgotPasswordDto => _forgotPasswordDto; set forgotPasswordDto(ForgotPasswordDto value) { _forgotPasswordDto = value; } UserAccountDto get userAccountDto => _userAccountDto; set userAccountDto(UserAccountDto value) { _userAccountDto = value; } bool get isAuthenticated => _isAuthenticated; LoginResponse get userResponse => _userResponse; set userResponse(LoginResponse value) { _userResponse = value; notifyListeners(); } Future<String> login(String email, String password) async{ authUseCase = new AuthUseCase(); dynamic responseFromWs = await authUseCase.login(email,password); return processToWsResponse<LoginResponse>(responseFromWs,LoginResponse,isForLogin: true); } Future<String> registerDriver(UserAccountDto userAccountDto) async { authUseCase = new AuthUseCase(); dynamic responseFromWs = await authUseCase.registerDriver(userAccountDto); return processToWsResponse<UserAccountDto>(responseFromWs,UserAccountDto); } Future<String> sendActivationCode(String email) async { authUseCase = new AuthUseCase(); dynamic responseFromWs = await authUseCase.sendActivationCode(email); return processToWsResponse<UserAccountDto>(responseFromWs,UserAccountDto); } Future<String> changePassword(ForgotPasswordDto data) async { authUseCase = new AuthUseCase(); dynamic responseFromWs = await authUseCase.changePassword(data); return processToWsResponse<UserAccountDto>(responseFromWs,UserAccountDto); } String processToWsResponse<T>( dynamic responseFromWs, dynamic T, {bool? isForLogin}){ String responseToShowToUser = ""; if(responseFromWs is! String) { if(isForLogin != null) { _isAuthenticated = true; notifyListeners(); print("valeur de authenticated "+isAuthenticated.toString()); } if(isForLogin != null) { userResponse = LoginResponse.fromMap(responseFromWs); } return ""; }else{ responseToShowToUser = responseFromWs; } return responseToShowToUser; } void logout() { _isAuthenticated = false; notifyListeners(); } }
main代码
var globalMessengerKey = GlobalKey<ScaffoldMessengerState>(); void main() { WidgetsFlutterBinding.ensureInitialized(); Future.wait([ SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]), //PrefUtils().init() ]).then((value) { runApp(MyApp()); }); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return Sizer( builder: (context, orientation, deviceType) { return MultiProvider( providers: [ ChangeNotifierProvider<AuthProvider>(create: (context) => AuthProvider()) ], builder : (context, child) => MaterialApp( title: 'trennko', debugShowCheckedModeBanner: false, theme: theme, localizationsDelegates: [ AppLocalizationDelegate(), GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate ], supportedLocales: [Locale('en', '')], home: Consumer<AuthProvider>( builder: (context, auth, child) { return auth.isAuthenticated ? HomePage() : LoginPage() ; } ) ) ); }, ); } }
问题原因
Provider管理的状态仅存储在内存中,当应用退出并重新启动时,所有内存中的状态都会被重置,_isAuthenticated会回到初始值false,导致App再次加载LoginPage。
解决方案
通过本地持久化存储(如SharedPreferences)保存认证状态,在Provider初始化时读取本地状态,登录和登出时同步更新本地存储。
修改后的AuthProvider代码
import 'package:shared_preferences/shared_preferences.dart'; import 'dart:convert'; class AuthProvider extends ChangeNotifier { bool _isAuthenticated = false; late AuthUseCase authUseCase; LoginResponse _userResponse = LoginResponse.empty(); UserAccountDto _userAccountDto = UserAccountDto.empty(); ForgotPasswordDto _forgotPasswordDto = ForgotPasswordDto(); // 持久化相关配置 final Future<SharedPreferences> _prefs = SharedPreferences.getInstance(); static const String _authStatusKey = 'is_authenticated'; static const String _userResponseKey = 'user_response'; // 构造函数中加载本地存储的认证状态 AuthProvider() { _loadSavedAuthState(); } // 从本地加载认证状态和用户信息 Future<void> _loadSavedAuthState() async { final SharedPreferences prefs = await _prefs; // 读取认证状态,默认false _isAuthenticated = prefs.getBool(_authStatusKey) ?? false; // 读取用户信息(可选,根据需求决定是否持久化) final String? userResponseJson = prefs.getString(_userResponseKey); if (userResponseJson != null) { _userResponse = LoginResponse.fromMap(jsonDecode(userResponseJson)); } notifyListeners(); } ForgotPasswordDto get forgotPasswordDto => _forgotPasswordDto; set forgotPasswordDto(ForgotPasswordDto value) { _forgotPasswordDto = value; } UserAccountDto get userAccountDto => _userAccountDto; set userAccountDto(UserAccountDto value) { _userAccountDto = value; } bool get isAuthenticated => _isAuthenticated; LoginResponse get userResponse => _userResponse; set userResponse(LoginResponse value) { _userResponse = value; notifyListeners(); } Future<String> login(String email, String password) async{ authUseCase = new AuthUseCase(); dynamic responseFromWs = await authUseCase.login(email,password); return processToWsResponse<LoginResponse>(responseFromWs,LoginResponse,isForLogin: true); } // 其他方法保持不变... String processToWsResponse<T>( dynamic responseFromWs, dynamic T, {bool? isForLogin}){ String responseToShowToUser = ""; if(responseFromWs is! String) { if(isForLogin != null) { _isAuthenticated = true; // 保存认证状态到本地 _prefs.then((prefs) => prefs.setBool(_authStatusKey, true)); notifyListeners(); print("valeur de authenticated "+isAuthenticated.toString()); } if(isForLogin != null) { _userResponse = LoginResponse.fromMap(responseFromWs); // 保存用户信息到本地(可选) _prefs.then((prefs) => prefs.setString(_userResponseKey, jsonEncode(responseFromWs))); notifyListeners(); } return ""; }else{ responseToShowToUser = responseFromWs; } return responseToShowToUser; } void logout() { _isAuthenticated = false; _userResponse = LoginResponse.empty(); // 清除本地存储的认证状态和用户信息 _prefs.then((prefs) { prefs.remove(_authStatusKey); prefs.remove(_userResponseKey); }); notifyListeners(); } }
额外配置
- 在
pubspec.yaml中添加shared_preferences依赖:
dependencies: flutter: sdk: flutter shared_preferences: ^2.2.2 # 版本号以最新为准
- 执行
flutter pub get安装依赖。
说明
- 持久化存储保证了应用重启后,认证状态不会丢失,用户无需重新登录。
- 除了
SharedPreferences,也可以使用Hive、SecureStorage等其他本地存储方案,根据安全性需求选择。 - 用户信息的持久化是可选的,若需要保留用户登录后的详细信息,可按照示例中的方式将其序列化为JSON存储。
内容的提问来源于stack exchange,提问作者Ramses Kouam
相关产品推荐
相关产品推荐

