Nadia Yaseen
Nadia Yaseen

Reputation: 81

how to update build method in flutter without causing memory leak

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?

Upvotes: 1

Views: 712

Answers (1)

FMorschel
FMorschel

Reputation: 864

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);
}

Upvotes: 1

Related Questions