Home > Software design >  How to use Streambuilder in flutter
How to use Streambuilder in flutter

Time:05-28

import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';

void main() async {
  //Run this first
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Smart Bin',
      home: new HomePageWidget(),
    );
  }
}

class HomePageWidget extends StatefulWidget {
  const HomePageWidget({Key key}) : super(key: key);

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

class _HomePageWidgetState extends State<HomePageWidget> {
  final scaffoldKey = GlobalKey<ScaffoldState>();
  final currentBinRecord = FirebaseFirestore.instance.collection("current_bin");


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: scaffoldKey,
      appBar: AppBar(
        title: Text(
          'SmartBin',
        ),
      ),
      body: SafeArea(
        child: GestureDetector(
          onTap: () => FocusScope.of(context).unfocus(),
          child: Column(
            mainAxisSize: MainAxisSize.max,
            children: [
              Expanded(
                child: StreamBuilder<List<CurrentBinRecord>>(
                  stream: queryCurrentBinRecord(
                    queryBuilder: (currentBinRecord) =>
                        currentBinRecord.orderBy('level', descending: true),
                  ),
                  builder: (context, snapshot) {
                    // Customize what your widget looks like when it's loading.
                    if (!snapshot.hasData) {
                      return Center(
                        child: SizedBox(
                          width: 50,
                          height: 50,
                          child: CircularProgressIndicator(),
                        ),
                      );
                    }
                    List<CurrentBinRecord> listViewCurrentBinRecordList =
                        snapshot.data;
                    return ListView.builder(
                      padding: EdgeInsets.zero,
                      scrollDirection: Axis.vertical,
                      itemCount: listViewCurrentBinRecordList.length,
                      itemBuilder: (context, listViewIndex) {
                        final listViewCurrentBinRecord =
                            listViewCurrentBinRecordList[listViewIndex];
                        return Row(
                          mainAxisSize: MainAxisSize.max,
                          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                          children: [
                            Text(
                              listViewCurrentBinRecord.area,
                            ),
                            Text(
                              listViewCurrentBinRecord.level.toString(),
                            ),
                          ],
                        );
                      },
                    );
                  },
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

This is the error

First error is:

child: StreamBuilder<List<CurrentBinRecord>>

The name 'CurrentBinRecord' isn't a type so it can't be used as a type argument. Try correcting the name to an existing type, or defining a type named 'CurrentBinRecord'.

Second error is:

stream: queryCurrentBinRecord

The method 'queryCurrentBinRecord' isn't defined for the type '_HomePageWidgetState'. Try correcting the name to the name of an existing method, or defining a method named 'queryCurrentBinRecord'.

Third error is:

List<CurrentBinRecord> listViewCurrentBinRecordList =
                        snapshot.data;

The name 'CurrentBinRecord' isn't a type so it can't be used as a type argument. Try correcting the name to an existing type, or defining a type named 'CurrentBinRecord'.

CodePudding user response:

These is the syntax try -

return StreamBuilder(
  stream: theStreamSource, // Eg a firebase query
  builder: (context, AsyncSnapshot snapshot) {
    if (!snapshot.hasData) {
       return Center(
         child: CircularProgressIndicator(),
       );
    }
    return ListView.builder(
        itemCount: snapshot.data.documents.length,
        itemBuilder: (context, int index) {
          return Text(snapshot.data.documents[index]['title']);
        }
    );
  },
);

Hope it helps.

CodePudding user response:

I think the best way to use StreamBuilder is to create separate controller class that can handle all your business logic and update UI.

// your widget class
class UIClass extends StatefulWidget {


  const UIClass({Key key}) : super(key: key);

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

class _UIClassState extends State<UIClass> {

  UIClassController<List<CurrentBinRecord>> _uiController;

  @override
  void initState() {
    _uiController = UIClassController(StreamController<List<CurrentBinRecord>>());
    super.initState();
  }
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text("Hello Everyone"),
        StreamBuilder<List<CurrentBinRecord>>(
          stream: _uiController.uiStream,
          builder: (context, snapshot) {
             if(snapshot.hasError){
               return ErrorWidget();
             }
             else if(snapshot.connectionState == ConnectionState.waiting){
               return WaitingWidget();
             }
             else if(snapshot.hasData){
               return ListView.builder(
                 padding: EdgeInsets.zero,
                 scrollDirection: Axis.vertical,
                 itemCount: snapshot.data.length,
                 itemBuilder: (context, listViewIndex) {
                   final listViewCurrentBinRecord =
                   snapshot.data[listViewIndex];
                   return Row(
                     mainAxisSize: MainAxisSize.max,
                     mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                     children: [
                       Text(
                         listViewCurrentBinRecord.area,
                       ),
                       Text(
                         listViewCurrentBinRecord.level.toString(),
                       ),
                     ],
                   );
                 },
               );
             }
             else{
               return SizedBox();
             }
          }
        ),
      ],
    );
  }

  @override
  void dispose() {
    super.dispose();
    _uiController.dispose();
  }
}


// controller class to handle all business logic
// you can also split it into multiple sub controllers
class UIClassController<T> {

  final StreamController<T> _controller;

  // If you are using this on multiple widgets then  use asBroadcastStream()
  Stream<T> get uiStream => _controller.stream;

  UIClassController(this._controller);

  void updateMyUI([dynamic params]){
       T t;
      // your logic //
      //------------//
      _controller.sink.add(t);
  }

  void dispose(){
    _controller.close();
  }

}
  • Related