代码之家  ›  专栏  ›  技术社区  ›  diegoveloper

带streams&rxdart的flutter重新加载列表

  •  5
  • diegoveloper  · 技术社区  · 7 年前

    我有一个关于如何在flutter中调用refresh indicator后使用streams和rxdart重新加载列表的问题。

    这是我的,我的模特班:

        class HomeState {
    
          List<Event> result;
          final bool hasError;
          final bool isLoading;
    
           HomeState({
            this.result,
            this.hasError = false,
            this.isLoading = false,
          });
    
          factory HomeState.initial() =>
              new HomeState(result: new List<Event>());
          factory HomeState.loading() => new HomeState(isLoading: true);
          factory HomeState.error() => new HomeState(hasError: true);
    
        }
    
    
        class HomeBloc {
    
          Stream<HomeState> state;
          final EventRepository repository;
    
          HomeBloc(this.repository) { 
            state = new Observable.just(new HomeState.initial());
          }
    
          void loadEvents(){
            state = new Observable.fromFuture(repository.getEventList(1)).map<HomeState>((List<Event> list){
              return new HomeState(
                  result: list,
                  isLoading: false 
              );    
            }).onErrorReturn(new HomeState.error())
            .startWith(new HomeState.loading());
          }
    
        }
    

    我的小部件:

        class HomePageRx extends StatefulWidget {
          @override
          _HomePageRxState createState() => _HomePageRxState();
        }
    
        class _HomePageRxState extends State<HomePageRx> {
          HomeBloc bloc;
    
          _HomePageRxState() {
            bloc = new HomeBloc(new EventRest());
            bloc.loadEvents();
          }
    
          Future<Null> _onRefresh() async {
            bloc.loadEvents();
            return null;
          }
    
          @override
          Widget build(BuildContext context) {
            return new StreamBuilder(
                stream: bloc.state,
                builder: (BuildContext context, AsyncSnapshot<HomeState> snapshot) {
                  var state = snapshot.data;
                  return new Scaffold(
                    body: new RefreshIndicator(
                      onRefresh: _onRefresh,
                      child: new LayoutBuilder(builder:
                          (BuildContext context, BoxConstraints boxConstraints) {
                        if (state.isLoading) {
                          return new Center(
                            child: new CircularProgressIndicator(
                              backgroundColor: Colors.deepOrangeAccent,
                              strokeWidth: 5.0,
                            ),
                          );
                        } else {
                          if (state.result.length > 0) {
                            return new ListView.builder(
                                itemCount: snapshot.data.result.length,
                                itemBuilder: (BuildContext context, int index) {
                                  return new Text(snapshot.data.result[index].title);
                                });
                          } else {
                            return new Center(
                              child: new Text("Empty data"),
                            );
                          }
                        }
                      }),
                    ),
                  );
                });
          }
        }
    

    问题是,当我从列表中提取刷新时,ui不刷新(服务器被调用,refreshIndicator的动画也被调用),我知道这个问题与流有关,但我不知道如何解决它。

    预期结果:在加载数据之前显示CircularProgressIndicator

    有什么帮助吗?谢谢

    1 回复  |  直到 7 年前
        1
  •  6
  •   Rémi Rousselet    7 年前

    你不应该改变 state .

    你应该提交一个新的价值观。以便 StreamBuilder ,它正在听 状态 将收到新值的通知。

    也就是说你不能 Observable 内部实例,如 可观察的 没有任何方法添加推送新值。所以你需要一个 Subject .

    基本上,这会将您的bloc更改为以下内容:

    class HomeBloc {
      final Stream<HomeState> state;
      final EventRepository repository;
      final Subject<HomeState> _stateSubject;
    
      factory HomeBloc(EventRepository respository) {
        final subject = new BehaviorSubject(seedValue: new HomeState.initial());
        return new HomeBloc._(
            repository: respository,
            stateSubject: subject,
            state: subject.asBroadcastStream());
      }
    
      HomeBloc._({this.state, Subject<HomeState> stateSubject, this.repository})
          : _stateSubject = stateSubject;
    
      Future<void> loadEvents() async {
        _stateSubject.add(new HomeState.loading());
    
        try {
          final list = await repository.getEventList(1);
          _stateSubject.add(new HomeState(result: list, isLoading: false));
        } catch (err) {
          _stateSubject.addError(err);
        }
      }
    }
    

    另外,请注意 loadEvent 使用 addError 只有一个例外。而不是推动 HomeState 用一个 hasError: true .