how to update build method in flutter without causing memory leak

354

You have no need to set state. The FutureBuilder already rebuilds it's build method when the future finishes. You can just put this FutureBuilder around anything you want to update and use the snapshot.data to process.

Just as a bonus tip: FutureBuilders have a initialData parameter so you can use that and be sure that you never receive null values for example!

Edit:

Here is an example of how to do something like what you want to achieve using Bloc's Cubit base class. You could do something like this and create this cubit variable up in your widget tree and then pass it down wherever you want. Wherever you use this NewWidget and pass the same variable instance they will all update together.

final cubit = DocGetter(
  () {
    return FirebaseFirestore.instance.collection('users').doc('userId').get()
  },
);

cubit.futureUpdate(
  FirebaseFirestore.instance.collection('users').doc('userId').get(),
);

cubit.futureUpdateFunction(
  FirebaseFirestore.instance.collection('users').doc('userId').get,
);

class NewWidget extends StatelessWidget {
  const NewWidget({
    Key? key,
    required this.child,
    required this.getter,
    this.childWhileEmpty,
  }) : super(key: key);

  final Widget child;
  final Widget? childWhileEmpty;
  final DocGetter getter;

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<Map>(
      initialData: cubit.state,
      stream: cubit.stream,
      builder: (context, snapshot) {
        final map = snapshot.data!;
        if (map.isEmpty) {
          return childWhileEmpty ?? const SizedBox.shrink();
        } else {
          return child;
        }
      },
    );
  }
}

class DocGetter extends Cubit<Map> {
  DocGetter(Future<Map> Function() fn, {Map? initialState})
      : super(initialState ?? {}) {
    fn().then(update);
  }

  Future<void> futureUpdateFunction(Future<Map> Function() fn) async {
    final map = await fn();
    emit(map);
  }

  Future<void> futureUpdate(Future<Map> futureMap) async {
    final map = await futureMap;
    emit(map);
  }

  void update(Map newMap) => emit(newMap);
}
Share:
354
Nadia Yaseen
Author by

Nadia Yaseen

Updated on January 03, 2023

Comments

  • Nadia Yaseen
    Nadia Yaseen over 1 year

    I have this code which fetch data from Firestore and I have setState during build, but it keeps giving warnings about memory leak, however it's updated, but I need a way that avoid this warning, here is simple sample

    bool isOne = false ;
    
    //Stfl Widget
    Widget build(BuildContext context) {
        return Stack( //edit
    children [
    !isOne? Text('bool varible is false')
                         :  Text('bool varible is true')
     FutureBuilder(
           future: FirebaseFirestore.instance.collection('users')
                      .doc('userId').get(),
            builder: (context, AsyncSnapshot snapshot) {
               if(!snapshot.hasData){
                     return Text('');
                  }else{ 
                      if(mounted) {
                          setState(() {
                          isOne = true ; // memory leak warning 
                              });
                       }
                   }  
               return snapshot.data['name'];
    
    

    also I tested this but the same warning

    WidgetsBinding.instance!.addPostFrameCallback((_) => setState(() {}));
    

    How can I handle that type of simple update during build tree without any memory leak causing?

    • Nadia Yaseen
      Nadia Yaseen about 2 years
      Josteve i just read your link but i need example similar for mine above sing management package , and thanks if you did it in answer to vote it
  • Yeasin Sheikh
    Yeasin Sheikh about 2 years
    Can you try with checking FutureBuilder's snapshot state like waiting and errors?
  • Josteve
    Josteve about 2 years
    You should use a state management package instead of calling setState repeatedly...See Riverpod here: riverpod.dev
  • Nadia Yaseen
    Nadia Yaseen about 2 years
    sorry it was my bad , please see my question again since i edit it , it is out Future widget
  • Felipe Morschel
    Felipe Morschel about 2 years
    I can see that, but you only need to swap the Stack and the FutureBuilder, put the Stack inside and process it all inside the FutureBuilder
  • Nadia Yaseen
    Nadia Yaseen about 2 years
    of course i can do it , but it is just similar simple for big other code that cannot do this way
  • Felipe Morschel
    Felipe Morschel about 2 years
    My suggestion then would be for you to look for other state management approaches. Something like Bloc or anything else where you can update a simple part of your code only and from far away in your widget tree. Would you like some better explanation into how to use Bloc (or Cubits that are simpler)? I could edit the comment to add that.
  • Nadia Yaseen
    Nadia Yaseen about 2 years
    yes sure thanks
  • Felipe Morschel
    Felipe Morschel about 2 years
    Updated the comment