David L
David L

Reputation: 1344

How to display a Firebase list in REAL TIME?

I have a TODO List function (Alarmas), but I feel I'm not taking advantage of Firebase's Realtime features enough.

The Widget displays the list very well, however when someone puts a new task from another cell phone, I am not being able to show it automatically, but I must call the build again by clicking on the "TODO button" in the BottomNavigationBar.

Is there a way that the new tasks are automatically displayed without doing anything?

I'm using streams to get the list...

@override
  Widget build(BuildContext context) {
    alarmaBloc.cargarAlarmas();

///---Scaffold and others

return StreamBuilder(
          stream: alarmaBloc.alarmasStream,
          builder: (BuildContext context, AsyncSnapshot<List<AlarmaModel>> snapshot){
            if (snapshot.hasData) {
              final tareasList = snapshot.data;
              if (tareasList.length == 0) return _imagenInicial(context);
            
              return ListView(

                children: [
                  for (var itemPendiente in tareasList)
                    _crearItem(context, alarmaBloc, itemPendiente),
                  //more widgets
                  ],
              );
            } else if (snapshot.hasError) {
              return Text(snapshot.error.toString());
            } 
              return Center (child: Image(image: AssetImage('Preloader.gif'), height: 200.0,));
          },
      ),

And, I read the Firebase Data in this way...

Future<List<AlarmaModel>> cargarAlarmas() async {

  final List<AlarmaModel> alarmaList = new List(); 

  Query resp = db.child('alarmas');

  resp.onChildAdded.forEach((element) {
        
        final temp = AlarmaModel.fromJson(Map<String,dynamic>.from(element.snapshot.value));
        temp.idAlarma = element.snapshot.key;
        alarmaList.add(temp);    // element.snapshot.value.
  });

  await resp.once().then((snapshot) {
    print("Total list was loaded - ${alarmaList.length}");
  }); //I'm using this await to be sure that the full list was loaded, so I can order and process it later

      return alarmaList;

}

How can I display a List from Firebase in "true" Real Time?

Upvotes: 0

Views: 153

Answers (1)

Frank van Puffelen
Frank van Puffelen

Reputation: 599011

To properly manage the state of asynchronously loaded data, you should:

  1. Start loading/listening to the data in initState()
  2. Set the data into the state (with setState()) when you receive it or it is updated.
  3. Then render it from the state in the build method.

So in your code that'd be something like:

final List<AlarmaModel> alarmaList = new List();  // this is now a field in the `State` object

@override
void initState() {
  super.initState();

  Query resp = db.child('alarmas');

  resp.onChildAdded.forEach((element) {
        final temp = AlarmaModel.fromJson(Map<String,dynamic>.from(element.snapshot.value));
        temp.idAlarma = element.snapshot.key;
        alarmaList.add(temp);

        setState(() {
          alarmaList = alarmaList;
        })
  });

}
@override
  Widget build(BuildContext context) {
    ///---Scaffold and others

    return StreamBuilder(
          stream: alarmaBloc.alarmasStream,
          builder: (BuildContext context, AsyncSnapshot<List<AlarmaModel>> snapshot){
            if (snapshot.hasData) {
              final tareasList = snapshot.data;  

If you only want to repaint once you've gotten a complete update from the database, you can put the call to setState() in a value listener, just use onValue in that instead of once(), as you also want to catch the updates.

Upvotes: 1

Related Questions