skip to Main Content

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


  1. Try this

    void addSelectedCar(String carId) {
      if (mounted) {
        setState(() {
          selectedCar.add(carId);
        });
      }
    }
    
    Login or Signup to reply.
  2. 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()

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search