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

如何通过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();
  }
}

额外配置

  1. 在pubspec.yaml中添加shared_preferences依赖:
dependencies:
  flutter:
    sdk: flutter
  shared_preferences: ^2.2.2 # 版本号以最新为准
  1. 执行flutter pub get安装依赖。

说明

  • 持久化存储保证了应用重启后,认证状态不会丢失,用户无需重新登录。
  • 除了SharedPreferences,也可以使用Hive、SecureStorage等其他本地存储方案,根据安全性需求选择。
  • 用户信息的持久化是可选的,若需要保留用户登录后的详细信息,可按照示例中的方式将其序列化为JSON存储。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 19:32:02