setState() called after dispose() causing error inside SpinKit package in flutter

Issue

In the given code I added a webview in which I’m trying to load a package called Spinkit.
Everything was working perfectly somehow I encounter this given error multiple times on my debug console. I’m new to flutter and do not know much about it. I tried if (mounted) but didn’t work for me.

here

// ignore_for_file: prefer_const_constructors
// ignore: use_key_in_widget_constructors
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';

void main(){
  SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
    statusBarColor: Color(0xff1e2229)
  ));
   runApp(MyApp());
}

 
class MyApp extends StatelessWidget {
 
  @override
  Widget build(BuildContext context) {
    return  MaterialApp(
            debugShowCheckedModeBanner: false,
            home:  Scaffold(
                       body: WebViewClass()
                      )
              );
  
  }
}
 
class WebViewClass extends StatefulWidget {
  WebViewState createState() => WebViewState();
}

class WebViewState extends State<WebViewClass> with TickerProviderStateMixin{

 late WebViewController _controller;

  final Completer<WebViewController> _controllerCompleter =
      Completer<WebViewController>();
  //Make sure this function return Future<bool> otherwise you will get an error
  Future<bool> _onWillPop(BuildContext context) async {
    if (await _controller.canGoBack()) {
      _controller.goBack();
      return Future.value(false);
    } else {
      return Future.value(true);
    }
  }

  @override
   void initState() {
     super.initState();
         // Enable hybrid composition.
    if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
   }

  bool isLoading = false;
  final key = UniqueKey();
  
  @override
  Widget build(BuildContext context) {
    return  WillPopScope(
      onWillPop: () => _goBack(context),
      child: Scaffold(
                resizeToAvoidBottomInset : false,
                appBar: null,
                body: SafeArea(
                    child: IgnorePointer(
                      ignoring: isLoading,
                      child: Stack(
                        children: [
                          WebView(
                            initialUrl: 'https://google.com',
                            javascriptMode: JavascriptMode.unrestricted,
                            key: key,
                            onPageFinished: (value) { 
                                if (mounted) {
                                  setState(() {
                                    isLoading = false;
                                  }); 
                                 }      
                            },
                            onPageStarted: (value) {
                                 if (mounted) {
                                    setState(() {
                                      isLoading = true;
                                    }); 
                                 }      
                            },
                            onWebViewCreated: (WebViewController webViewController) {
                              _controllerCompleter.future.then((value) => _controller = value);
                              _controllerCompleter.complete(webViewController);
                            },
                          ),
                         

                          isLoading ? Container(
                            width: MediaQuery.of(context).size.width,
                            height: MediaQuery.of(context).size.height,
                            color: Colors.grey.withOpacity(0.5),
                            child: Center(child: SpinKitDualRing(
                                                    color: Colors.pinkAccent,
                                                    size: 45.0,
                                                    controller: AnimationController(vsync: this,duration: const Duration(milliseconds: 1200)),
                                                  )
                                          )  ,
                          ) : Container(),
                          
                        ],
                      ),
                    )),));

  }

 Future<bool> _goBack(BuildContext context) async {
    if (await _controller.canGoBack()) {
      _controller.goBack();
      return Future.value(false);
    } else {
      showDialog(
          context: context,
          builder: (context) => AlertDialog(
                title: Text('Do you want to exit from Foodrive?'),
                actions: <Widget>[
                  TextButton(
                    onPressed: () {
                      Navigator.of(context).pop();
                    },
                    child: Text('No'),
                  ),
                  TextButton(
                    onPressed: () {
                      SystemNavigator.pop();
                    },
                    child: Text('Yes'),
                  ),
                ],
              ));
      return Future.value(true);
    }
  } 


}

Solution

Replace to this build method

  int position = 0;
  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () => _goBack(context),
      child: Scaffold(
        resizeToAvoidBottomInset: false,
        appBar: null,
        body: SafeArea(
          child: IndexedStack(
            index: position,
            children: [
              WebView(
                initialUrl: 'https://google.com',
                javascriptMode: JavascriptMode.unrestricted,
                key: key,
                onPageStarted: (value) {
                  setState(() {
                    position = 1;
                  });
                },
                onPageFinished: (value) {
                  setState(() {
                    position = 0;
                  });
                },
                onWebViewCreated: (WebViewController webViewController) {
                  _controllerCompleter.future
                      .then((value) => _controller = value);
                  _controllerCompleter.complete(webViewController);
                },
              ),
              Container(
                width: MediaQuery.of(context).size.width,
                height: MediaQuery.of(context).size.height,
                color: Colors.grey.withOpacity(0.5),
                child: Center(
                  child: SpinKitDualRing(
                    color: Colors.pinkAccent,
                    size: 45.0,
                    controller: AnimationController(
                      vsync: this,
                      duration: const Duration(milliseconds: 1200),
                    ),
                  ),
                ),
              )
            ],
          ),
        ),
      ),
    );
  }

full code

import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';

void main() {
  SystemChrome.setSystemUIOverlayStyle(
    const SystemUiOverlayStyle(statusBarColor: Color(0xff1e2229)),
  );
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: WebViewClass(),
      ),
    );
  }
}

class WebViewClass extends StatefulWidget {
  WebViewState createState() => WebViewState();
}

class WebViewState extends State<WebViewClass> with TickerProviderStateMixin {
  late WebViewController _controller;

  final Completer<WebViewController> _controllerCompleter =
      Completer<WebViewController>();
  //Make sure this function return Future<bool> otherwise you will get an error
  Future<bool> _onWillPop(BuildContext context) async {
    if (await _controller.canGoBack()) {
      _controller.goBack();
      return Future.value(false);
    } else {
      return Future.value(true);
    }
  }

  @override
  void initState() {
    super.initState();
    // Enable hybrid composition.
    if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
  }

  bool isLoading = false;
  final key = UniqueKey();

  void setLoading(bool value) {
    if (mounted) {
      WidgetsBinding.instance?.addPostFrameCallback((_) async {
        isLoading = value;
        setState(() {});
      });
    }
  }

  int position = 0;

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () => _goBack(context),
      child: Scaffold(
        resizeToAvoidBottomInset: false,
        appBar: null,
        body: SafeArea(
          child: IndexedStack(
            index: position,
            children: [
              WebView(
                initialUrl: 'https://google.com',
                javascriptMode: JavascriptMode.unrestricted,
                key: key,
                onPageStarted: (value) {
                  setState(() {
                    position = 1;
                  });
                },
                onPageFinished: (value) {
                  setState(() {
                    position = 0;
                  });
                },
                onWebViewCreated: (WebViewController webViewController) {
                  _controllerCompleter.future
                      .then((value) => _controller = value);
                  _controllerCompleter.complete(webViewController);
                },
              ),
              Container(
                width: MediaQuery.of(context).size.width,
                height: MediaQuery.of(context).size.height,
                color: Colors.grey.withOpacity(0.5),
                child: Center(
                  child: SpinKitDualRing(
                    color: Colors.pinkAccent,
                    size: 45.0,
                    controller: AnimationController(
                      vsync: this,
                      duration: const Duration(milliseconds: 1200),
                    ),
                  ),
                ),
              )
            ],
          ),
        ),
      ),
    );
  }

  Future<bool> _goBack(BuildContext context) async {
    if (await _controller.canGoBack()) {
      _controller.goBack();
      return Future.value(false);
    } else {
      showDialog(
          context: context,
          builder: (context) => AlertDialog(
                title: Text('Do you want to exit from Foodrive?'),
                actions: <Widget>[
                  TextButton(
                    onPressed: () {
                      Navigator.of(context).pop();
                    },
                    child: Text('No'),
                  ),
                  TextButton(
                    onPressed: () {
                      SystemNavigator.pop();
                    },
                    child: Text('Yes'),
                  ),
                ],
              ));
      return Future.value(true);
    }
  }
}

Answered By – Saied Islam Shuvo

Answer Checked By – Katrina (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *