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

Flutter中SharedPreferences变更时如何实现页面自动刷新跳转?

解决SharedPreferences登录状态变更后页面自动切换的问题

问题描述

当前通过SharedPreferences存储loginStatus标记登录状态,用FutureBuilder在AuthScreen中判断状态并跳转对应页面,但登录/登出修改SharedPreferences后,页面不会自动切换,必须重启App才生效。

问题根源

FutureBuilder依赖的loginCheckFuture仅在AuthScreen的initState中初始化执行一次,后续SharedPreferences的状态变更不会触发Future重新执行,也没有通知UI更新;同时登录/登出操作只修改了存储,没有触发页面的重建或导航逻辑。

解决方案

方案1:使用StreamBuilder监听状态变化

通过全局Stream广播登录状态的变更,用StreamBuilder替代FutureBuilder,实时响应状态变化。

  1. 定义全局StreamController:
final loginStatusStream = StreamController<bool>.broadcast();
  1. 修改AuthScreen为StreamBuilder实现:
class AuthScreen extends StatefulWidget {
  const AuthScreen({super.key});

  @override
  State<AuthScreen> createState() => _AuthScreenState();
}

class _AuthScreenState extends State<AuthScreen> {
  final Future<SharedPreferences> _prefs = SharedPreferences.getInstance();

  Future<bool> _checkInitialLoginStatus() async {
    final SharedPreferences prefs = await _prefs;
    return prefs.getBool('loginStatus') ?? false;
  }

  @override
  void initState() {
    super.initState();
    // 初始化时获取初始状态并发送到Stream
    _checkInitialLoginStatus().then((status) {
      loginStatusStream.add(status);
    });
  }

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<bool>(
      stream: loginStatusStream.stream,
      initialData: false, // 首次启动默认未登录
      builder: (context, snapshot) {
        Widget child;
        if (snapshot.hasData) {
          child = snapshot.data! ? const TabsScreen() : const LoginScreen();
        } else {
          child = const SplashScreen();
        }
        return Scaffold(body: child);
      },
    );
  }
}
  1. 更新登录/登出方法,触发Stream事件:
// 登录按钮逻辑
void _fnBtnLogin(BuildContext context) async {
  final SharedPreferences prefs = await SharedPreferences.getInstance();
  await prefs.setBool('loginStatus', true);
  loginStatusStream.add(true);
}

// 登出弹窗逻辑
void _submitAlertDialog(context) async {
  final SharedPreferences prefs = await SharedPreferences.getInstance();
  await prefs.remove('loginStatus');
  loginStatusStream.add(false);
}

方案2:使用状态管理库(以Provider为例)

通过状态管理统一维护登录状态,状态变化时自动通知UI更新,适合中大型项目。

  1. 创建AuthProvider:
class AuthProvider extends ChangeNotifier {
  bool _isLoggedIn = false;
  final Future<SharedPreferences> _prefs = SharedPreferences.getInstance();

  bool get isLoggedIn => _isLoggedIn;

  AuthProvider() {
    _loadInitialStatus();
  }

  Future<void> _loadInitialStatus() async {
    final SharedPreferences prefs = await _prefs;
    _isLoggedIn = prefs.getBool('loginStatus') ?? false;
    notifyListeners();
  }

  Future<void> login() async {
    final SharedPreferences prefs = await _prefs;
    await prefs.setBool('loginStatus', true);
    _isLoggedIn = true;
    notifyListeners();
  }

  Future<void> logout() async {
    final SharedPreferences prefs = await _prefs;
    await prefs.remove('loginStatus');
    _isLoggedIn = false;
    notifyListeners();
  }
}
  1. 在main.dart中注册Provider:
void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => AuthProvider(),
      child: const MyApp(),
    ),
  );
}
  1. 修改AuthScreen监听Provider状态:
class AuthScreen extends StatelessWidget {
  const AuthScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Consumer<AuthProvider>(
      builder: (context, authProvider, _) {
        final Widget screen = authProvider.isLoggedIn 
            ? const TabsScreen() 
            : const LoginScreen();
        return Scaffold(body: screen);
      },
    );
  }
}
  1. 更新登录/登出方法:
// 登录按钮逻辑
void _fnBtnLogin(BuildContext context) async {
  await Provider.of<AuthProvider>(context, listen: false).login();
}

// 登出弹窗逻辑
void _submitAlertDialog(context) async {
  await Provider.of<AuthProvider>(context, listen: false).logout();
}

方案3:手动导航回AuthScreen(简单直接)

登录/登出完成后,直接导航到AuthScreen,让它重新判断状态,适合小型项目快速实现。

// 登录按钮逻辑
void _fnBtnLogin(BuildContext context) async {
  final SharedPreferences prefs = await SharedPreferences.getInstance();
  await prefs.setBool('loginStatus', true);
  // 替换当前页面为AuthScreen
  Navigator.pushReplacement(
    context,
    MaterialPageRoute(builder: (context) => const AuthScreen()),
  );
}

// 登出弹窗逻辑
void _submitAlertDialog(context) async {
  final SharedPreferences prefs = await SharedPreferences.getInstance();
  await prefs.remove('loginStatus');
  // 替换当前页面为AuthScreen
  Navigator.pushReplacement(
    context,
    MaterialPageRoute(builder: (context) => const AuthScreen()),
  );
}

方案对比

  • 方案1:无需第三方库,适合简单场景,但需注意全局Stream的生命周期管理。
  • 方案2:代码结构清晰,状态管理统一,适合中大型项目扩展。
  • 方案3:实现成本最低,但会有页面切换动画,用户体验略逊。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 20:35:10