【问题标题】:Flutter Reloading List with Streams & RxDartFlutter Reloading List with Streams & RxDart
【发布时间】:2018-11-28 18:46:16
【问题描述】:

我有一个关于如何在 Flutter 中使用 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

有什么帮助吗?谢谢

【问题讨论】:

    标签: dart flutter reactive-programming


    【解决方案1】:

    您不应该更改state 的实例。

    您应该向 observable 提交一个新值。这样正在监听stateStreamBuilder 将收到一个新值的通知。

    这意味着您不能只在内部拥有一个 Observable 实例,因为 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 例外。而不是用hasError: true 推送HomeState

    【讨论】:

    • 好人,谢谢,我需要学习响应式编程。
    • 您可能需要添加一个工厂构造函数,以便您可以将state 作为最终结果传递
    • @diegoveloper 我编辑了我的示例以包含工厂构造函数
    • 谢谢,你有关于这些概念的任何参考/页面 Subjects/Observable/Stream/Sink/ 等...?
    • You can use the documentation of ReactiveX。最后 rxdart 只是 rx 的一个 dart 实现。至于 Sink/Stream 本身,如果你了解 Observables 你应该了解 Stream/Sink
    猜你喜欢
    • 2022-11-09
    • 1970-01-01
    • 2019-07-19
    • 2019-07-23
    • 1970-01-01
    • 2019-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多