Flutter/Firebase: How to reduce StreamBuilder call on push/pop call?

Issue

I have a screen with a bottomNavigationBar:

class AttendantMainPage extends StatefulWidget {
  final String? email;

  AttendantMainPage({
    Key? key,
    this.email,
  }) : super(key: key);

  @override
  _AttentdantMainPageState createState() => _AttentdantMainPageState();
}

class _AttentdantMainPageState extends State<AttendantMainPage> {
  var user = FirebaseAuth.instance.currentUser;
  int _currentIndex = 1;
  late final List<Widget> _children;

  @override
  void initState() {
    _children = [
      ProfilePage(),
      AttendantHomePage(),
      ChatListPage(),
    ];
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _children[_currentIndex],
      bottomNavigationBar: BottomNavigationBar(
        backgroundColor: Colors.white,
        selectedItemColor: Color(0xffe96cbd),
        onTap: onTabPressed,
        currentIndex: _currentIndex,
        items: [
          BottomNavigationBarItem(
              icon: new Icon(
                CustomIcons.user,
              ),
              label: 'Profile'),
          BottomNavigationBarItem(
              icon: new Icon(
                CustomIcons.home,
              ),
              label: 'Home'),
          BottomNavigationBarItem(
              icon: new Icon(
                Icons.mail,
              ),
              label: 'Messages'),
        ],
      ),
    );
  }

  void onTabPressed(int index) {
    setState(() {
      _currentIndex = index;
    });
  }
}

And i have streamBuilder in all of the screens. When I’m changing screens my stream builders are being called again and again. It may be really expensive using firebase i guess. Here is code of one of the screens, can someone tell me how to avoid unneccessary calls after switching between pages?

class ProfilePage extends StatefulWidget {
  @override
  _ProfilePageState createState() => _ProfilePageState();
}

class _ProfilePageState extends State<ProfilePage> {
  bool enabled = false;
  late FocusNode myFocusNode;
  var user = FirebaseAuth.instance.currentUser;
  late Stream<DocumentSnapshot> stream;

  @override
  void initState() {
    stream = FirebaseFirestore.instance
        .collection('users')
        .doc(user!.uid)
        .snapshots();
    myFocusNode = FocusNode();

    super.initState();
  }

  @override
  void dispose() {
    // Clean up the focus node when the Form is disposed.
    myFocusNode.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    double _width = MyUtility(context).width;
    double _height = MyUtility(context).height;
    return Scaffold(
      backgroundColor: Color(0xfff0eded),
      body: SingleChildScrollView(
        physics: NeverScrollableScrollPhysics(),
        child: Container(
          width: _width,
          height: _height,
          child: Column(
            children: [
              Stack(
                alignment: AlignmentDirectional.topCenter,
                children: [
                  Container(
                    width: _width,
                    height: _height * 0.4,
                  ),
                  Container(
                    height: _height * 0.25,
                    decoration: BoxDecoration(
                      gradient: LinearGradient(
                        begin: Alignment.topRight,
                        end: Alignment.bottomLeft,
                        colors: [
                          Color(0xff4d629f),
                          Color(0xffe96cbd),
                        ],
                      ),
                    ),
                  ),
                  Positioned(
                    bottom: _height * 0.02,
                    child: ProfileImage(
                      width: _width * 0.5,
                      height: _height * 0.25,
                      userEmail: user!.email!,
                    ),
                  ),
                  Positioned(
                    right: _width * 0.25,
                    bottom: _height * 0.05,
                    child: ClipOval(
                      child: Container(
                        color: Colors.white,
                        child: Padding(
                          padding: const EdgeInsets.all(2),
                          child: ClipOval(
                            child: Material(
                              color: Color(0xffe96cbd), // button color
                              child: InkWell(
                                splashColor: Color(0xffffc2ea), // inkwell color
                                child: SizedBox(
                                    width: _width * 0.08,
                                    height: _height * 0.04,
                                    child: Padding(
                                      padding: const EdgeInsets.all(8.0),
                                      child: Icon(
                                        Icons.edit,
                                        color: Colors.white,
                                        size: MyUtility(context).width * 0.04,
                                      ),
                                    )),
                                onTap: () {
                                  getImage().then((value) {
                                    uploadFile(value);
                                  });
                                },
                              ),
                            ),
                          ),
                        ),
                      ),
                    ),
                  ),
                ],
              ),
              Stack(
                alignment: AlignmentDirectional.topCenter,
                children: [
                  Padding(
                    padding: EdgeInsets.symmetric(
                      vertical: 10,
                      horizontal: _width * 0.05,
                    ),
                    child: OverlayPanel(
                      width: _width * 0.9,
                      child: Padding(
                        padding: EdgeInsets.all(
                          _height * 0.04,
                        ),
                        child: Column(
                          children: [
                            StreamBuilder<DocumentSnapshot>(
                                stream: stream,
                                builder: (context, snapshot) {
                                  if (snapshot.hasData) {
                                    return TextFormField(
                                      focusNode: myFocusNode,
                                      enabled: enabled,
                                      initialValue: snapshot.data!['username'],
                                      textAlign: TextAlign.center,
                                      style: TextStyle(
                                        fontSize: 30,
                                        color: Color(0xff273150),
                                      ),
                                      onFieldSubmitted: (input) {
                                        setState(() {
                                          enabled = false;
                                        });
                                        print(input);
                                        FirebaseFirestore.instance
                                            .collection('users')
                                            .doc(user!.uid)
                                            .update({'username': input});
                                      },
                                    );
                                  } else
                                    return TextField(
                                      enabled: false,
                                      style: TextStyle(fontSize: 30),
                                    );
                                }),
                            SizedBox(
                              height: _height * 0.02,
                            ),
                            Text(user!.email!,
                                style: TextStyle(
                                  fontSize: 18.0,
                                  color: Color(0xff273150),
                                )),
                            Text(
                              //TODO great idea to use currentUser: user!.displayName as a user Type to check it all easier and faster
                              'Type: ${'Attendant'}',
                              style: TextStyle(
                                fontSize: 14.0,
                                color: Color(0xff273150),
                              ),
                            ),
                          ],
                        ),
                      ),
                    ),
                  ),
                  Positioned(
                    right: _width * 0.1,
                    top: _height * 0.025,
                    child: ClipOval(
                      child: Container(
                        color: Colors.white,
                        child: Padding(
                          padding: const EdgeInsets.all(2),
                          child: ClipOval(
                            child: Material(
                              color: Color(0xffe96cbd), // button color
                              child: InkWell(
                                splashColor: Color(0xffffc2ea), // inkwell color
                                child: SizedBox(
                                    width: _width * 0.08,
                                    height: _width * 0.08,
                                    child: Padding(
                                      padding: const EdgeInsets.all(8.0),
                                      child: Icon(
                                        Icons.edit,
                                        color: Colors.white,
                                        size: _width * 0.04,
                                      ),
                                    )),
                                onTap: () async {
                                  setState(() {
                                    enabled = !enabled;
                                  });
                                  await Future.delayed(
                                      Duration(milliseconds: 10),
                                      () => {
                                            FocusScope.of(context)
                                                .requestFocus(myFocusNode),
                                          });
                                },
                              ),
                            ),
                          ),
                        ),
                      ),
                    ),
                  ),
                ],
              ),
              Padding(
                padding: const EdgeInsets.symmetric(vertical: 10.0),
                child: Container(
                  width: _width,
                  decoration: BoxDecoration(
                    color: Color(0xfff0eded),
                  ),
                  child: Container(
                    child: Column(
                      children: [
                        CustomButton(
                          width: _width * 0.9,
                          icon: Icons.lock,
                          text: 'Change Password',
                          onPressed: () {
                            //TODO add possibility to change password
                          },
                        ),
                        CustomButton(
                          width: _width * 0.9,
                          icon: Icons.delete,
                          text: 'Delete Account',
                          onPressed: () {},
                        ),
                        CustomButton(
                          width: _width * 0.9,
                          icon: Icons.logout,
                          text: 'Log Out',
                          onPressed: () async {
                            await FirebaseAuth.instance.signOut();
                            Navigator.pop(context);
                          },
                        ),
                      ],
                    ),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Solution

Changing body in my AttendantMainPage from:

  body: _children[_currentIndex],

to

   body: IndexedStack(
        index: _currentIndex,
        children: _children,
      ),

Solved the problem.

Thanks for help guys!

Answered By – Darexad

Answer Checked By – Senaida (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *