How to show different Widget when user is offline while using StreamBuilder?

778

You can add Error to Stream and catch it in StreamBuilder like this:

_someStreamCtrl.addError(error);  // Client is offline

And in StreamBuilder:

StreamBuilder<String>(
      stream: someStream,
      initialData: [],
      builder: (BuildContext context,
          AsyncSnapshot<String> snap) {
        if (snap.hasError)
            return ErrorWidget(); //Error
        if (snap.hasData)
          return // Desired widget

        //if waiting
          return CircularProgressIndicator();
        );
      },
    );
Share:
778
Pritish
Author by

Pritish

Updated on December 08, 2022

Comments

  • Pritish
    Pritish over 1 year

    I am trying to fetch some data from the internet. With the use of FutureBuilder, handling for various cases like offline, online,error is quite easy but I am using StreamBuilder and I am not able to understand how to handle offline case

    Following is my code to use StreamBuilder which works but I have not handled offline data or error

    return StreamBuilder(
          builder: (context, AsyncSnapshot<SchoolListModel> snapshot) {
            if (snapshot.hasError) {
              return Expanded(
                  child: Center(
                child: Text(SOMETHING_WENT_WRONG),
              ));
            }
    
            if (!snapshot.hasData) {
              return Expanded(
                child: Center(
                  child: CircularProgressIndicator(),
                ),
              );
            }
    
            if (snapshot.data != null) {
              if (snapshot.data.status == 1) {
                return buildSchoolList(snapshot.data.schoolListData);
              } else {
                showMessageDialog(snapshot.data.msg.toString(), context);
              }
            }
            },
          stream: schoolListBloc.schoolList,
        );
      }
    

    Now to handle the offline case I am doing the following two options which don't work in my case

    Option one.

    return StreamBuilder(
          builder: (context, AsyncSnapshot<SchoolListModel> snapshot) {
           switch (snapshot.connectionState) {
              case ConnectionState.none:
                return Text(SOMETHING_WENT_WRONG);
              case ConnectionState.active:
              case ConnectionState.waiting:
                return Expanded(
                  child: Center(
                    child: CircularProgressIndicator(),
                  ),
                );
              case ConnectionState.done:
                if (snapshot.hasError) {
                  return errorData(snapshot);
                } else {
                  if (snapshot.data.status == 1) {
                    return buildSchoolList(snapshot.data.schoolListData);
                  } else {
                    showMessageDialog(snapshot.data.msg.toString(), context);
                  }
                }
            }
          },
          stream: schoolListBloc.schoolList,
        );
      }
    

    I keep seeing the CircularProgressIndicator and no error on the console. I fail to understand why the above switch case works for FuturBuilder and not StreamBuilder.

    Second Option.

    Future<bool> checkInternetConnection() async {
      try {
        final result = await InternetAddress.lookup('google.com');
        if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
          print('connected');
          return true;
        }
      } on SocketException catch (_) {
        print('not connected');
        return false;
      }
      return false;
    }
    
    
    return StreamBuilder(
          builder: (context, AsyncSnapshot<SchoolListModel> snapshot) {
           checkInternetConnection().then((isAvailable) {
              if (isAvailable) {
                if (!snapshot.hasData || snapshot.data == null) {
                  return Center(
                    child: CircularProgressIndicator(),
                  );
                }
    
                if (snapshot.data != null) {
                  if (snapshot.data.status == 1) {
                    return buildSchoolList(snapshot.data.schoolListData);
                  } else {
                    showMessageDialog(snapshot.data.msg.toString(), context);
                  }
                }
              } else {
                return Center(
                  child: Column(
                    children: <Widget>[
                      Text(CHECK_YOUR_INTERNET_CONNECTION),
                      RaisedButton(
                        onPressed: () {},
                        child: Text(TRY_AGAIN),
                      )
                    ],
                  ),
                );
              }
            }); },
          stream: schoolListBloc.schoolList,
        );
      }
    

    Using this option throws the following error

    the following assertion was thrown building StreamBuilder<SchoolListModel>(dirty, state:
    I/flutter ( 5448): _StreamBuilderBaseState<SchoolListModel, AsyncSnapshot<SchoolListModel>>#dd970):
    I/flutter ( 5448): A build function returned null.
    I/flutter ( 5448): The offending widget is: StreamBuilder<SchoolListModel>
    I/flutter ( 5448): Build functions must never return null. To return an empty space that causes the building widget to
    I/flutter ( 5448): fill available room, return "new Container()". To return an empty space that takes as little room as..
    

    What approach should I take with the following cases of offline, online and error data when using StreamBuilder