Bloc Pattern隐藏和取消隐藏小部件

时间:2019-02-01 08:56:01

标签: dart flutter bloc

我正在尝试从互联网上获取一些数据并将其显示为列表。

以下是我的bloc代码

class StudentsBloc {
  final _repository = Repository();
  final _students = BehaviorSubject<StudentModel>();

  final BehaviorSubject<bool> _showProgress = BehaviorSubject<bool>();
  final BehaviorSubject<bool> _showNoInternetViews = BehaviorSubject<bool>();

  Observable<StudentModel> get students => _students.stream;
  Observable<bool> get showProgress => _showProgress.stream;
  Observable<bool> get showNoInternetViews => _showNoInternetViews.stream;

  //FetchStudent from my Api
  fetchStudents(String disciplineId, String schoolId, String year_id,
      String lastIndex) async {
    final student = await _repository.fetchStudents(
        disciplineId, schoolId, year_id, lastIndex);
    _students.sink.add(student);
  }

  //Check to see if user has internet or not
  isNetworkAvailable(String disciplineId, String schoolId, String year_id,
      String lastIndex) async {
    checkInternetConnection().then((isAvailable) {
      if (isAvailable) {
        fetchStudents(disciplineId, schoolId, year_id, lastIndex);
      } else {
        _students.sink.addError(NO_NETWORK_AVAILABLE);
      }
    });
  }

  Function(bool) get changeVisibilityOfProgress => _showProgress.sink.add;
  Function(bool) get changeVisibilityOfNoInternetViews =>
      _showNoInternetViews.sink.add;

  dispose() {
    _students.close();
    _showProgress.close();
    _showNoInternetViews.close();
  }
}

以下是我隐藏统一控件的主要代码

Widget buildList(StudentsBloc bloc) {
    return StreamBuilder(
      stream: bloc.students,
      builder: (context, AsyncSnapshot<StudentModel> snapshot) {
        if (snapshot.hasError) {
          bloc.changeVisibilityOfProgress(false);
          bloc.changeVisibilityOfNoInternetViews(true);

          return StreamBuilder(
            stream: bloc.showNoInternetViews,
            builder: (context, snapshot) {
              bool showNoInternetView = snapshot.hasData ?? false;

              return Visibility(
                child: Center(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      Text("No Network Available"),
                      RaisedButton(
                        onPressed: () {
                          fetchStudents();
                        },
                        child: Text("Retry"),
                      )
                    ],
                  ),
                ),
                visible: showNoInternetView ? true : false,
              );
            },
          );
        }

        if (snapshot.hasData) {
          bloc.changeVisibilityOfProgress(false);
          bloc.changeVisibilityOfNoInternetViews(false);

          return Refresh(
            year_id: "2",
            schoolId: "1",
            lastIndex: "0",
            disciplineId: "1",
            child: ListView.builder(
              itemBuilder: (context, int index) {
                return buildTile(
                    snapshot.data.toBuilder().data.studentData[index]);
              },
              itemCount: snapshot.data.toBuilder().data.studentData.length,
            ),
          );
        }

        if (!snapshot.hasData) {
          return StreamBuilder(
            builder: (context, snapshot) {
              bool showProgressIndicator = snapshot.data ?? false;

              return Visibility(
                child: Center(
                  child: CircularProgressIndicator(),
                ),
                visible: showProgressIndicator ? true : false,
              );
            },
            stream: bloc.showProgress,
          );
        }
      },
    );
  }

buildList的{​​{1}}中调用body方法

Scaffold

假设打开应用程序时用户可以上网,那么我可以看到void fetchStudents() { bloc?.changeVisibilityOfNoInternetViews(false); bloc?.changeVisibilityOfProgress(true); bloc?.isNetworkAvailable("1", "1", "2", "0"); } ,然后可以看到数据列表 但假设开始时打开应用程序且用户没有互联网,那么我会显示“无网络可用文本”和一个重试按钮, 现在,如果用户已连接到Internet,然后单击按钮重试,则几秒钟后我将直接看到数据列表,而不是circularprogressindicator。我无法理解为什么circularprogressindicator是在显示数据列表之前单击重试按钮,则不会隐藏并且显示NoInternetviews

我的流在调用的重试按钮上没有得到更新。 progressindicator中有关于StreamBuilder的警告吗?

我尝试更改答案中的StreamBuilder,如@ivenxu所述,但仍然无法正常工作。 以下是附加代码的链接 https://drive.google.com/file/d/15Z8jXw1OpwTB1CxDS8sHz8jKyHhLwJp7/view?usp=sharing https://drive.google.com/open?id=1gIXV20S1o5jYRnno_NADabuIj4w163fF

2 个答案:

答案 0 :(得分:1)

在视图层中,可以使用 Visibility()小部件并在从Internet加载数据时传递可见参数true或false。 让我们考虑一下如何从bloc更改可见变量。 Visibility()的父级使用 StreamBuilder()小部件以流式传输更改数据。 对于您的情况,您需要在您的Bloc内部使用 PublishSubject 来流式传输和添加新数据,并且需要 Observable 来在小部件上流式传输这些数据。

让我们显示一个片段代码以帮助您如何实现它

该集团包含 PublishSubject Observable 以便流式传输和添加数据

  //this Subject allows sending data, error and done events to the listener
  final PublishSubject<bool> _progressStateSubject = new PublishSubject();

  //the listener are streaming on changes
  Observable<bool> get progressStateStream => _progressStateSubject.stream;

  //to change your progress state
  void changeProgressState({bool state}) => _progressStateSubject.sink.add(state);

您可以在此处更改进度状态

void callWebService() async {
    //when you call your func to fetch your data change your state to true
    changeProgressState(state: true);
    .
    .
    .
    if(response != null){
      //when your call is done change the state to false
      changeProgressState(state: false);
    }
  }

您的进度小部件是

// Loading Widget
  Widget _buildLoadingWidget(Bloc bloc) {
    return StreamBuilder<bool>(
        stream: bloc.progressStateStream,//streaming on changes
        builder: (context, snapshot) {
          return Visibility(
            visible: snapshot.data ?? false,//calling when data changes
            child: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Text("Loading data from API...",
                      textDirection: TextDirection.ltr),
                  CircularProgressIndicator()
                ],
              ),
            ),
          );
        });
  }

答案 1 :(得分:0)

原因似乎是CircularProgressIndicator位于学生流的更新周期之内。在重试的情况下,当从网络电话返回数据时,学生只会获得下一个快照。

尝试更改流构建器的顺序,尝试将学生流构建器放入进度流构建器中。

Widget buildList(StudentsBloc bloc) {
    return StreamBuilder(
      stream: bloc.showProgress,
      builder: (context, snapshot) {
        bool showProgressIndicator = snapshot.data ?? false;
        if (!showProgressIndicator) {
             StreamBuilder(
            stream: bloc.students,
            builder: (context, AsyncSnapshot<StudentModel> snapshot) {
               ....
               //your original code without progress StreamBuilder
            }
        }
        return Visibility(
        child: Center(
            child: CircularProgressIndicator(),
        ),
        visible: showProgressIndicator ? true : false,
        );
    },

    );
  }