i’ve built a card which will open a searchDelegate where users can search for cars. When selecting a car, the delegate screen will close onTap: () {close(context, carList[index].id);}
. The id will then be updated on the main screen and added to a List.
However, i keep having the error setState() called after dispose()
List<String> selectedCar = [];
// Function to open SearchDelegate
void openCarSearchDelegate() async {
String? selectedCarId = await showSearch(
context: context,
delegate: CompareCarSearchDelegate(_firebaseServices.carsRef),
);
print(selectedCarId) // <- Returns value when car is selected
if (selectedCarId != null) {
addSelectedCar(selectedCarId);
}
}
// Update the state to add to the List
void addSelectedCar(String carId) {
// ERROR occurs here
setState(() {
selectedCar.add(carId);
});
}
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(20),
child: SelectCarCard(
selectedCar: selectedCar1,
color: inactive,
onTap: openCarSearchDelegate,
),
);
}
class SelectCarCard extends StatelessWidget {
const SelectCarCard({
Key? key,
required this.onTap,
}) : super(key: key);
final void Function() onTap;
@override
Widget build(BuildContext context) {
return InkWell(
borderRadius: const BorderRadius.all(Radius.circular(12)),
onTap: onTap,
child: Ink(
height: 200,
width: double.infinity,
child: SizedBox(
height: 200,
width: double.infinity,
child: const Text(
"Select Car",
style: TextStyle(
color: Colors.black,
fontSize: 18,
),
),
),
),
);
}
}
class CompareCarSearchDelegate extends SearchDelegate<String> {
final Query searchQuery;
CompareCarSearchDelegate(this.searchQuery);
@override
String get searchFieldLabel => 'Select car...';
@override
TextStyle get searchFieldStyle => const TextStyle(fontSize: 18);
@override
List<Widget> buildActions(BuildContext context) {
// Clear field
}
@override
Widget buildLeading(BuildContext context) {
// Return to previous screen
}
@override
Widget buildResults(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: searchQuery.snapshots(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator(
backgroundColor: Colors.white,
color: kPrimaryColor,
strokeWidth: 3,
);
}
List<DocumentSnapshot> documents = snapshot.data!.docs;
final carList = documents.where((doc) {
// Get results based on search text
}).toList();
return ListView.separated(
separatorBuilder: (context, index) {
return const Divider();
},
shrinkWrap: true,
padding:
const EdgeInsets.only(top: 20, bottom: 20, left: 10, right: 10),
itemCount: carList.length,
itemBuilder: (context, index) {
return ListTile(
contentPadding: const EdgeInsets.only(right: 10),
title: Text(
carList[index]['name'],
overflow: TextOverflow.ellipsis,
),
onTap: () {
close(context, carList[index].id);
},
);
},
);
},
);
}
@override
Widget buildSuggestions(BuildContext context) {
return Container();
}
}
I/flutter (28352): setState() called after dispose(): _BodyState#27420(lifecycle state: defunct, not mounted)
I/flutter (28352): 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.
I/flutter (28352): 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.
I/flutter (28352): 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().
I have tried adding if(mounted) {setState(() {selectedCar.add(carId);});}
but the mounted
keeps returning false.
Any idea of how i can implement it or any solution would be greatly appreciated. Thanks.
2
Answers
Try this
Is your
close(context, carList[index].id);
function async?If it is then replace
onTap: () { close(context, carList[index].id)},
with
onTap: () async {await close(context, carList[index].id)},
.If not, then your error indicates that there is some async call which is responsible for the call of
setState()