fluttersharedpreferencesflutter-futurebuilder

How to refresh pages when snapshot.data changes in flutter?


I have shared preferences called 'loginStatus' where to store login status data whether user is login or not using future builder. if false then user is push to loginScreen, if true then user is push to tabsScreen. So the snapshot.data return false in the very first of the beginning using app.

class AuthScreen extends StatefulWidget {
  const AuthScreen({super.key});

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

class _CheckAuthScreenState extends State<AuthScreen> {
  final Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
  late Future<bool> loginCheckFuture;

  Future<bool> _checkIfLoggedIn() async {
    final SharedPreferences prefs = await _prefs;
    var isAuth = prefs.getBool('loginStatus');
    if (isAuth != null && isAuth == true) {
      return true;
    }
    return false;
  }

  @override
  void initState() {
    super.initState();
    loginCheckFuture = _checkIfLoggedIn();
  }

  @override
  Widget build(BuildContext context) {
    Widget child;
    return FutureBuilder(
      future: loginCheckFuture,
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          if (snapshot.data == true) {
            child = const TabsScreen();
          } else {
            child = const LoginScreen();
          }
        } else {
          child = const SplashScreen();
        }
        return Scaffold(
          body: child,
        );
      },
    );
  }
}

At loginScreen() I have login button that store shared preferences makes snapshot.data now should be true

void _fnBtnLogin(BuildContext context) async {
    final SharedPreferences prefs = await _prefs;
    await prefs.setBool('loginStatus', true);
  }

By changing snapshot.data, I expected to change the screen from loginScreen to tabScreen directly. But it failed the result is user still at the loginScreen.

Of course if I reload the app, the screen now directs to tabScreen.

The same case when I try to logout user in profileScreen by remove shared preference and change snapshot.data, the screen still in the profileScreen, but when I reload it, it successfully directs to loginScreen.

void _submitAlertDialog(context) async {
    final SharedPreferences prefs = await _prefs;
    await prefs.remove('loginStatus');
  }

I expect the result is to change the screen directly from loginScreen to TabScreen when there is changes in shared preferences.


Solution

  • A Future<> and the FutureBuilder get you one result. Once the result is in, the build is finalized.

    What you are looking for is a Stream<> and corresponding StreamBuilder, to receive multiple events during the lifetime of your application.

    However, instead of building it all yourself, I would suggest you take a look at the Business Logic Components pattern, implemented by the package flutter_bloc by the incredible BLoC library. They have an example for exactly your situation.