Flutter: Items in StreamBuilder(Using firebase realtime database) are sorted randomly

5,656

When you call snap.data.snapshot.value; the data in the snapshot (which is ordered) is converted to a Map<String, Object> which isn't ordered. To maintain the order, you'll want to listen to onChild... instead.

Note that FlutterFire has a convenient firebase_list library that handles most of the heavy lifting of onChild... for you.

Also see:

Share:
5,656
Wilson Wilson
Author by

Wilson Wilson

Freelance Flutter developer. I occasionally dream in Dart.

Updated on December 19, 2022

Comments

  • Wilson Wilson
    Wilson Wilson over 1 year

    I'm creating a simple application with Firebase Realtime database where a user inputs a text and it gets added to a list of chats.

    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.indigo,
          ),
          home: MyHomePage(),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      var _firebaseRef = FirebaseDatabase().reference().child('chats');
      TextEditingController _txtCtrl = TextEditingController();
    
      @override
      Widget build(BuildContext context) {
        var comments = _firebaseRef.orderByChild('time').limitToLast(10);
        return Scaffold(
          body: Container(
            child: SafeArea(
              child: Column(
                children: <Widget>[
                  Container(
                      child: Row(children: <Widget>[
                    Expanded(child: TextField(controller: _txtCtrl)),
                    SizedBox(
                        width: 80,
                        child: OutlineButton(
                            child: Text("Add"),
                            onPressed: () {
                              sendMessage();
                            }))
                  ])),
                  StreamBuilder(
                    stream: comments.onValue,
                    builder: (context, snap) {
                      if (snap.hasData &&
                          !snap.hasError &&
                          snap.data.snapshot.value != null) {
                        Map data = snap.data.snapshot.value;
                        List item = [];
    
                        data.forEach(
                            (index, data) => item.add({"key": index, ...data}));
    
                        return Expanded(
                          child: ListView.builder(
                            itemCount: item.length,
                            itemBuilder: (context, index) {
                              return ListTile(
                                title: Text(item[index]['message']),
                              );
                            },
                          ),
                        );
                      } else
                        return Center(child: Text("No data"));
                    },
                  ),
                ],
              ),
            ),
          ),
        );
      }
    
      sendMessage() {
        _firebaseRef.push().set({
          "message": _txtCtrl.text,
          'time': DateTime.now().millisecondsSinceEpoch
        });
      }
    
    
    }
    

    It stores and retrieves data perfectly. But when I try adding data, the new items are placed at random points in the list.

    For example, in the image below, the last item I placed into the list was 'Nine'. But it was put in the center of the list:

    enter image description here

    I've tried sorting the list by timestamps, but it did nothing.

    What could be causing this issue? And how can I fix it?