1

I am using FirebaseAnimatedList in a Flutter/Dart chat app. The simplified build() method is as follows:

@override Widget build(BuildContext context) { return new Scaffold( appBar: AppBar( title: Text(_onLineStatus), // <-- This text value changed using setState() ), body: Column( children: <Widget>[ Flexible( child: FirebaseAnimatedList( query: reference, sort: (a, b) => b.key.compareTo(a.key), padding: EdgeInsets.all(8.0), reverse: true, itemBuilder: (BuildContext context, DataSnapshot snapshot, Animation<double> animation, int index) { return ChatMessage(snapshot: snapshot, animation: animation); }, ), ), Divider(height: 1.0), Container( decoration: BoxDecoration(color: Theme.of(context).cardColor), child: _buildTextComposer(), ) ], )); } 

I want to change the value of _onLineStatus on line 5 based on an event value returned by a listener, basically to indicate if the other chat participant in on or off line. I want any change to the status to reflect immediately. The obvious way to do this is to use setState() but of course this triggers a full rerun of the build() method which therefore reruns the FirebaseAnimatedList query, downloading the same data once again. I want to avoid this.

All examples of the use of FirebaseAnimatedList show it as part of the build() method yet we are recommended to avoid putting database calls into build() to avoid these side-effects, because build() can be run multiple times.

My questions therefore are:

  1. How can I move the call to FirebaseAnimatedList outside of the build() method so that I can use setState() to update the value of the AppBar title: property WITHOUT it rerunning FirebaseAnimatedList?

OR...

  1. How can I update the value of the AppBar title: property without rerunning the build() method ie. without calling setState()?

1 Answer 1

1

Create a StateFullWidget containing your app bar. Something like this:

Widget build(BuildContext context) { return new Scaffold( appBar: CustomAppBar(), body: Column( ... 

And then your new appbar widget:

class CustomAppBar extends StatefulWidget { @override _CustomAppBarState createState() => _CustomAppBarState(); } class _CustomAppBarState extends State<CustomAppBar> { String _onLineStatus = "online"; @override Widget build(BuildContext context) { return AppBar( title: Text(_onLineStatus), ); } } 

in this way you can independently rebuild the appbar from the list. You need to call setState in your new widget.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for your answer. Makes sense. I will only be able to try it out tomorrow and will get back to you then.
Sorry for slow response. I had to move my listener into the new widget in order to call setState() to change the status, which has lead to a whole lot of other issues cos I need the listener in the calling page as well. So at the moment I have two active listeners doing the same thing. Thanks again. BTW, you code returns a second app bar rather than just the app bar title, so I modified it a bit from my use.
Having multiple listeners is not a problem. When it gets complex I would recommend exploring the Provider lib. Very useful for state management.
Thanks @jbarat. My app currently uses scoped_model and I will be looking at replacing it with Provider later this year given that scoped_model is being deprecated at the end of 2020.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.