Why doesn't my StatefulWidget dissappear after dispose in Flutter?

28 Views Asked by At

I have worked with Flutter now and I know the cycles of the widgets quite well. I have a Login-Logic inside my code:

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

  @override
  State<Login> createState() => _LoginWidgetState();
}

class _LoginWidgetState extends State<Login> with WidgetsBindingObserver {

  @override
  void initState() {
    super.initState();
    Connectivity().checkConnectivity().then((connectivityResult) {
      setState(() {
        isConnected = connectivityResult != ConnectivityResult.none;
      });
    });

    _connectivitySubscription = Connectivity()
        .onConnectivityChanged
        .listen((ConnectivityResult result) {
      if (result == ConnectivityResult.none) {
        setState(() {
          isConnected = false;
        });
      } else {
        setState(() {
          isConnected = true;
        });
      }
    });
    print("init");
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void dispose() {
    print("dispose-login");
    _connectivitySubscription.cancel();
    WidgetsBinding.instance?.removeObserver(this);
    super.dispose();
  }

... more code
}

In this view, the form and validation happens. As soon as everything fine, I call this function:

login(String email, String password) async { ApiService apiService = ApiService(this);

final response = await apiService.postUnauthenticated(
    "", {"email": email, "password": password});

if (response.statusCode == 200) {
  final jsonResponse = jsonDecode(response.body);
  final token = jsonResponse['token'] as String;
  apiService.setAuthToken(token);
  saveAuthorizationToken(token);
  _token = token;
  _status = Status.authenticated;
  print("Status: Authenticated");
  notifyListeners();
} else {
  apiService.removeAuthToken();
  removeAuthorizationToken();
  _status = Status.unauthenticated;
  notifyListeners();
}

notifyListeners();
getAccessToken();
return response.statusCode;

}

In which I call the Api and set a status based on the output. With this status, I check which view to show in app.dart:

  @override
  Widget build(BuildContext context) {
    final authProvider = Provider.of<AuthProvider>(context, listen: false);
    return Consumer<AuthProvider>(
      builder: (context, user, child) {
        switch (user.status) {
          case Status.hasBikes:
            print("hasBike");
            return const HomePage();
          case Status.uninitialized:
            print("uninitialized");
            return const InitView();
          case Status.unauthenticated:
            print("unauth");
            return const Login();
          case Status.authenticated:
            print("auth");
            return const LoadView();
          case Status.unpaired:
            print("unpair");
            return const PairingHome(hasError: false);
          case Status.error:
            print("error");
            return const ServerError();
          default:
            return const InitView();
        }
      },
    );
  }

In another StatefulWidget the user can logout and gets redirected to the login page. This looks like this:

onTap: () async {
              Provider.of<AuthProvider>(context, listen: false).logout();
              Navigator.push(
                context,
                MaterialPageRoute(builder: (context) => const Login()),
              );
            }

So the problem is following. After the download, the user is on the login page. The login works flawless, including the redirect. But when the user logs out and tries to login again, the user gets logged in but not redirected. He has to reopen the app before he is logged in. And the weirdest part is that after login, the dispose-function of the Login-Page is called (i checked with a print), but the page is still displayed.

Do you have any idea about what could be the problem?

3

There are 3 best solutions below

0
Jay Pratap singh On

I think you can try by removing listen : false in provider when you calling in widget

0
Ivo On

You are pushing to another, a second, Login screen. I believe you shouldn't be pushing anything. It will already be handled automatically by the

switch (user.status) {

you have. So try to change

    onTap: () async {
              Provider.of<AuthProvider>(context, listen: false).logout();
              Navigator.push(
                context,
                MaterialPageRoute(builder: (context) => const Login()),
              );
            }

to

    onTap: () async {
              Provider.of<AuthProvider>(context, listen: false).logout();
            }
0
Hamid Waezi On

Because after you logout, your Consumer will add login page to your context, so you dont need to push login page.