Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Widget should be refresh when its data belongs to StreamBuilder's stream in flutter

I am creating a simple EXPENSE MANAGER app

I have divided screen in two section

Top Section for showing Two card of TotalIncome and TotalExpense
and other section is showing All Transactions

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Here, I have taken Streambuilder for showing all transaction, and with the help of this stream builder I have created Tow Global Variable totalincome and totalexpense

and showing total income and totalexpense to top section’s Card

When I add any transaction, List of transaction refresh properly as it is due to Stream Builder but total income and expense card not refreshing…

here I want the proper way to do it…(
like creating a method that fetch records from firebase and store into a List and to use this list for various needs…

here Is my code

Widget headerSummary(Size size) {
    return Container(
      height: size.height * 0.15,
      decoration: BoxDecoration(
        color: Colors.blue,
        borderRadius: BorderRadius.only(
            bottomRight: Radius.circular(30), bottomLeft: Radius.circular(30)),
      ),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          Expanded(

            child: SummaryCard(
              color: Colors.green,
              amount: totalincome.toString(),
              icondata: Icons.arrow_upward,
              title: 'Income',
            ),
          ),
          Expanded(
            child: SummaryCard(
              color: Colors.red,
              amount: totalexpense.toString(),
              icondata: Icons.arrow_downward,
              title: 'Expense',
            ),
          ),

        ],
      ),
    );
  }

transaction

Widget showTransactions(Size size) {
    return Container(
      height: size.height * .65,
      // color: Colors.red,
      child: StreamBuilder(
          stream: FirebaseFirestore.instance
              .collection('users')
              .doc(widget.loggeduser.userid)
              .collection('expenses').orderBy("date",descending: true)
              .snapshots(),
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.active) {
              if (snapshot.hasData) {
                QuerySnapshot querysnapshot =
                snapshot.data as QuerySnapshot;
                if (querysnapshot.docs.length > 0) {
                  List<Map<String, dynamic>> transactionlist = [];
                  for (int x = 0; x < querysnapshot.docs.length; x++) {
                    Map<String, dynamic> expensemap = querysnapshot.docs[x]
                        .data() as Map<String, dynamic>;
                    transactionlist.add(expensemap);
                  }

                   var x=transactionlist.where((element) => element['isexpense']==true).toList();
                  totalexpense=x.fold(0, (previousValue, element) => previousValue+element['amount']);


                  var y=transactionlist.where((element) => element['isexpense']==false).toList();
                  totalincome=y.fold(0, (previousValue, element) => previousValue+element['amount']);
//I have edited this lines...





                  return ListView.builder(
                    //reverse: true,
                      padding: EdgeInsets.symmetric(vertical: 10),
                      itemCount: transactionlist.length,
                      itemBuilder: (context, index) {

                       final trans=TransactionModel.fromjson(transactionlist[index]);
                       print(trans.toString());
                        return TransactionCard(
                          amount: trans.amount.toStringAsFixed(2),
                          datetime: trans.date.toString(),
                          paymentby: trans.paymentmode,
                          category: trans.category.title,
                          categoryicon: trans.category.iconurl,
                          isexpense: trans.isexpense,
                        );
                      });//listview end
                } else {
                  return Container(
                      child: Center(
                          child: Text('No Transaction Found...')));
                }
              } else {
                if (snapshot.hasError) {
                  return Text('error found');
                } else {
                  return Text('empty..');
                }
              }
            } else {
              return Center(child: CircularProgressIndicator());
            }
          }),
    );
  }

enter image description here

>Solution :

StreamBuilder will refresh its child UI, not the upper widget.

You can use ValueNotifier with ValueListenableBuilder. This snippet will help you to clear the concept.

class MyHomePage extends StatefulWidget {
  MyHomePage({
    Key? key,
  }) : super(key: key);

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

int? myGlobalValue1;

ValueNotifier<int?> globalValueNotifier = ValueNotifier(null);

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text("myGlobalValue1 $myGlobalValue1"),
            ValueListenableBuilder<int?>(
                valueListenable: globalValueNotifier,
                builder: (context, value, child) {
                  return Text("globalValueNotifier $value");
                }),
            StreamBuilder<int>(
              stream: Stream<int>.periodic(const Duration(seconds: 1), (x) => x)
                  .take(15),
              builder: (BuildContext context, AsyncSnapshot snapshot) {
                myGlobalValue1 = snapshot.data;

                WidgetsBinding.instance.addPostFrameCallback((_) {
                  globalValueNotifier.value = snapshot.data; // to skip initOn frame build
                });
                return Column(
                  children: [
                    Text(
                      snapshot.data != null ? snapshot.data.toString() : "0",
                    ),
                    Text("myGlobalValue1 inside streamB $myGlobalValue1"),
                  ],
                );
              },
            )
          ],
        ),
      ),
    );
  }
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading