I was trying to implement a loading bar after I click the register button on the Registration page and then I got this error I cannot figure out a way to show loading bar after the button is clicked
error:
[ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: setState() called after dispose(): _AdminRegisterState#f3c8f(lifecycle state: defunct, not mounted)
E/flutter (29660): This error happens if you call setState() on a State object for a widget that no longer appears in the widget tree (e.g., whose parent widget no longer includes the widget in its build). This error can occur when code calls setState() from a timer or an animation callback.
E/flutter (29660): The preferred solution is to cancel the timer or stop listening to the animation in the dispose() callback. Another solution is to check the "mounted" property of this object before calling setState() to ensure the object is still in the tree.
E/flutter (29660): This error might indicate a memory leak if setState() is being called because another object is retaining a reference to this State object after it has been removed from the tree. To avoid memory leaks, consider breaking the reference to this object during dispose().
E/flutter (29660): #0 State.setState.<anonymous closure> (package:flutter/src/widgets/framework.dart:1073:9)
E/flutter (29660): #1 State.setState (package:flutter/src/widgets/framework.dart:1108:6)
E/flutter (29660): #2 _AdminRegisterState.addAndCreateUser (package:election/pages/Admin/AdminRegister.dart:94:5)
E/flutter (29660): <asynchronous suspension>
E/flutter (29660): #3 _AdminRegisterState.build.<anonymous closure> (package:election/pages/Admin/AdminRegister.dart:215:31)
E/flutter (29660): <asynchronous suspension>
E/flutter (29660):
AdminRegister.dart:
import 'dart:math';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:election/pages/Admin/AdminHome.dart';
import 'package:election/services/Validator.dart';
import 'package:flutter/material.dart';
import 'package:election/services/Auth.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:loader_overlay/loader_overlay.dart';
class AdminRegister extends StatefulWidget {
const AdminRegister({Key? key}) : super(key: key);
@override
State<AdminRegister> createState() => _AdminRegisterState();
}
class _AdminRegisterState extends State<AdminRegister> {
String? get _errorText {
// at any time, we can get the text from _controller.value.text
final text = _controllerpassword.value.text;
// final email = _controlleremail.value.text;
// final name = _controllerName.value.text;
// final repass = _controllerrepassword.value.text;
// final phone = _controllerphone.value.text;
if (text.isEmpty) {
return 'Can\'t be empty';
}
if (text.length < 8) {
return 'atleast 8 characters requierd';
}
// return null if the text is valid
return null;
}
String? errormessage = '';
String? errorAddUser = '';
late String Name;
late String Email;
late String Phone;
late String Password;
late String Admin_Key;
bool _istrue = true;
bool _isloading = false;
final TextEditingController _controllerName = TextEditingController();
final TextEditingController _controlleremail = TextEditingController();
final TextEditingController _controllerphone = TextEditingController();
final TextEditingController _controllerpassword = TextEditingController();
final TextEditingController _controllerrepassword = TextEditingController();
final TextEditingController _controllerAdminKey = TextEditingController();
//create user metheod using firebase auth
Future<void> createUserWithEmailAndPassword() async {
setState(() { _isloading = true; });
try {
await Auth().createUserwithEmailAndPassword(email: _controlleremail.text, password: _controllerpassword.text);
if(mounted){
Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (context) => AdminHome()),(route) => false);
}else{return;}
} on FirebaseAuthException catch (e) {
setState(() {
errormessage = e.message;
});
}
setState(() { _isloading = false; });
}
//cloud firestore using firestore
final CollectionReference Admins = FirebaseFirestore.instance.collection('Admins');
Future<void>addUser()async{
Name = _controllerName.text;
Email=_controlleremail.text;
Password=_controllerpassword.text;
Phone=_controllerphone.text;
Admin_Key=_controllerAdminKey.text;
try{
await Admins.doc(Email).set({
"Name":Name,"email":Email,"password":Password,"phone":Phone,"Admin":_istrue,"private_key":Admin_Key});
print('user added successfullyyyyyyy');
}catch(err){
}
}
Future<void>addAndCreateUser()async{
setState(() { _isloading = true; });
await createUserWithEmailAndPassword();
await addUser();
setState(() { _isloading = false; });
}
Widget _errorMessage() {
return Text(errormessage == '' ? '' : 'Humm $errormessage');
}
@override
Widget build(BuildContext context) {
if(_isloading){
return const Scaffold(
backgroundColor: Colors.cyan,
body: Center(
child: CircularProgressIndicator(),
),
);
}else{
return Scaffold(
appBar: AppBar(
title: const Text(
"Register as Admin",
style: TextStyle(
color: Colors.cyan, fontWeight: FontWeight.bold, fontSize: 24),
),
),
body: Container(
margin: const EdgeInsets.all(16),
color: Colors.cyan,
child: Center(
child: SingleChildScrollView(
child: Container(
padding: EdgeInsets.all(8),
child: Column(
children: [
const SizedBox(
height: 24,
),
Container(
padding: EdgeInsets.all(16),
child: TextField(
controller: _controllerName,
decoration: const InputDecoration(
hintText: 'Name',
border: OutlineInputBorder(
borderRadius:
BorderRadius.all(Radius.circular(8))))),
),
const SizedBox(
height: 4,
),
Container(
padding: EdgeInsets.all(16),
child: TextField(
controller: _controlleremail,
decoration: const InputDecoration(
hintText: 'email id',
border: OutlineInputBorder(
borderRadius:
BorderRadius.all(Radius.circular(8))))),
),
const SizedBox(
height: 4,
),
Container(
padding: EdgeInsets.all(16),
child: TextField(
controller: _controllerphone,
keyboardType: TextInputType.number,
decoration: const InputDecoration(
hintText: 'phone number',
border: OutlineInputBorder(
borderRadius:
BorderRadius.all(Radius.circular(8))))),
),
const SizedBox(
height: 4,
),
Container(
padding: EdgeInsets.all(16),
child: TextField(
controller: _controllerpassword,
decoration: const InputDecoration(
hintText: 'password',
border: OutlineInputBorder(
borderRadius:
BorderRadius.all(Radius.circular(8))))),
),
const SizedBox(
height: 4,
),
Container(
padding: EdgeInsets.all(16),
child: TextField(
controller: _controllerrepassword,
decoration: const InputDecoration(
hintText: 'Re enter password',
border: OutlineInputBorder(
borderRadius:
BorderRadius.all(Radius.circular(8))))),
),
const SizedBox(
height: 4,
),
Container(
padding: const EdgeInsets.all(16),
child: TextField(
controller: _controllerAdminKey,
decoration: const InputDecoration(
hintText: 'Metamask Private key',
border: OutlineInputBorder(
borderRadius:
BorderRadius.all(Radius.circular(8))))),
),
const SizedBox(
height: 24,
),
ElevatedButton(
onPressed: () async {
if (_controllerpassword.text.isNotEmpty && _controlleremail.text.isNotEmpty) {
if(_controllerAdminKey.text.isNotEmpty&&_controllerName.text.isNotEmpty){
if(_controllerphone.text.isNotEmpty&&_controllerpassword.text==_controllerrepassword.text){
await addAndCreateUser();
}
}
}
},
style: ElevatedButton.styleFrom(primary: Colors.white),
child: const Text(
'Register as Admin',
style: TextStyle(color: Colors.cyan),
),
)
],
),
),
),
),
),
);
}
}
}
The loader is coded at the widget build method and the set state is used in the addAndCreateUser() function
In your code, the issue is that _isloading = false
is being called even after you are redirected to AdminHome
. When the account is created Navigator.pushAndRemoveUntil
is called and the user is redirected to AdminHome
. Because you have not set mounted
check on setState
when setting _isLoading = false
and the screen is disposed, you are getting this exception. Your code should look like this:
Future<void> createUserWithEmailAndPassword() async {
...
...
...
if (mounted) {
setState(() { _isloading = false; });
}
}
P.S I would suggest setting _isLoading
to false
when the account is created.