Home > Mobile >  Flutter Unhandled Exception: This widget has been unmounted, so the State no longer has a context (a
Flutter Unhandled Exception: This widget has been unmounted, so the State no longer has a context (a

Time:01-23

I've already checked the previous answer but can't help me.

I'm checking that user has internet or not if not then I'm showing pic of no internet. Now I've a button of Retry where user can click on it to check if he has internet back.

Now here I'm facing error when i click on Retry button

Unhandled Exception: This widget has been unmounted, so the State no longer has a context (and should be considered defunct). E/flutter (25542): Consider canceling any active work during "dispose" or using the "mounted" getter to determine if the State is still active.

My Updated splash screen

class SplashScreen extends StatefulWidget {
  const SplashScreen({Key? key}) : super(key: key);

  @override
  State<SplashScreen> createState() => _SplashScreenState();
}

class _SplashScreenState extends State<SplashScreen> {
  Future<bool> isLoggedIn() async {
    final prefs = await SharedPreferences.getInstance();
    final token = prefs.getString("token");
    print("Token obtained: $token");
    return token != null;
  }

  @override
  void initState() {
    _init();
    super.initState();
  }

  Future<void> _init() async {
    bool isConnected = await NetworkHelper.checkInternet();
    if (!isConnected) {
      if (mounted) {
        Navigator.pushReplacement(
          context,
          MaterialPageRoute(
              builder: (context) => CheckConnection(
                    onRetry: _init,
                  )),
        );
      }
    } else {
      await Future.delayed(const Duration(seconds: 3), () async {
        final isTokenValid = await isLoggedIn();
        if (isTokenValid) {
          if (mounted) {
            Navigator.pushReplacement(
              context,
              MaterialPageRoute(builder: (context) => BottomNav()),
            );
          }
        } else {
          if (mounted) {
            Navigator.pushReplacement(
              context,
              MaterialPageRoute(builder: (context) => Signup()),
            );
          }
        }
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        color: Colors.white,
        child: FlutterLogo(size: MediaQuery.of(context).size.height),
      ),
    );
  }
}

Here is my image showing if there is no internet.

class CheckConnection extends StatelessWidget {
  final VoidCallback onRetry;
  const CheckConnection({Key? key, required this.onRetry}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Image.asset("assets/image/no_internet.jpg"),
          const SizedBox(height: 20),
          ElevatedButton(
            onPressed: onRetry,
            child: const Text("Retry"),
          ),
        ],
      ),
    );
  }
}

CodePudding user response:

You have problems in your code. You are trying to access the context after what's called asynchronous suspension, i.e., you are accessing the context after some Future has done its work, while at that instance, the context might be in an invalid state, maybe because the Element tree has changed during this "asyncronois suspension". I also assume you are getting a warning about this but you are ignoring it.

The solution to this problem is, as the error suggests, use the getter mounted which is available inside the State class, after your Future does its work and before you access the context:

await Future.delayed(...);
if(mounted){
   // you can use the context
}
else{
   // you can't use the context
}

In your case, you need to check if the context is still valid by checking mounted variable before using it after a Future returns:

if(mounted) // you should put this check in all places where you use context after an asyncronous suspension
{
          Navigator.pushReplacement(
            context,
            MaterialPageRoute(builder: (context) => BottomNav()),
          );
}
else{
// the context is not valid
// you should handle this case according to your app needs
}

Also see this answer.

  • Related