【问题标题】:Merging streams in a Bloc在一个 Bloc 中合并流
【发布时间】:2020-08-21 19:03:13
【问题描述】:

我的集团中有一些流。我不确定这是否是正确和正确的方法,因为我是 Flutter 和 Bloc 模式的新手。 但是我怎样才能将 Bloc 中的流合并为一个呢?

欢迎任何关于该主题的提示......

我的 Bloc 文件

import 'package:flutter/material.dart';
import 'package:rxdart/rxdart.dart';

class WelcomeBloc {
  final _controller = PublishSubject<PageController>();
  final _page = PublishSubject<int>();
  final _lastPage = PublishSubject<bool>();

  Stream<dynamic> get combinedStream =>
      CombineLatestStream.list([getController, currentPage, isLastPage]);

  Stream<PageController> get getController => _controller.stream;
  Stream<int> get currentPage => _page.stream;
  Stream<bool> get isLastPage => _lastPage.stream;

  updatePage(int page) {
    _page.sink.add(page);
  }

  updatePageState(bool state) {
    _lastPage.sink.add(state);
  }

  dispose() {
    _controller.close();
    _page.close();
    _lastPage.close();
  }
}

final welcomeBloc = WelcomeBloc();

消费者

import 'package:flutter/material.dart';
import '../../blocs/welcome_bloc.dart';
import './pages/page.dart';
import './pages/page2.dart';
import './pages/login.dart';

class ViewerWrapper extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return StreamBuilder(
        stream: welcomeBloc.combinedStream,
        builder: (context, AsyncSnapshot snapshot) {
          return PageView(
            children: <Widget>[
              Page1(),
              Page2(),
              Login(),
            ],
            onPageChanged: (page) {
              welcomeBloc.updatePage(page);
              print(snapshot.data._page);
              // welcomeBloc.updatePage(page + 1);
            },
            // controller: snapshot.data.getController,
          );
        });
  }
}

【问题讨论】:

  • 合并是什么意思?
  • @AnirudhBagri 感谢您来到这里,伙计!)我的意思是,在我的 Bloc 文件中,我有三个流,但在 StreamBuilder 中,我只能订阅一个流。因此,据我所知,我应该将它们合并在一起,以便可以在我的 StreamBuilder 中使用它。我尝试使用combinedlatest,但它为我返回null。我想我在那里做错了什么。

标签: flutter flutter-dependencies rxdart


【解决方案1】:

您可以使用Rx.combineLatest3 喜欢this link 合并流,但正如我从您的代码中理解的那样,最好定义一个这样的模型:

Class MyModel{

    PageController pageController;
    int currentPage;
    bool isLastPage;
...

}

然后有一个与之配合使用的流。

编辑:将模型应用于代码

我用两种方法更改了代码。

第一个

您可以定义一个模型并使用该模型,因此您不需要 3 个不同的流,如果您始终需要组合流版本而不是任何其他地方的每个流,这没关系。

我在一个文件中编写了代码。

import 'package:flutter/material.dart';
import 'package:rxdart/rxdart.dart';

class MyModel {
  PageController pageController;
  int currentPage;
  bool isLastPage;

  MyModel({this.currentPage, this.pageController, this.isLastPage});
}

class WelcomeBloc {
  var _myModel = PublishSubject<MyModel>();

  Stream<MyModel> get getModel => _myModel.stream;

  // updatePage(int page) {
  //   _page.sink.add(page);
  // }

  // updatePageState(bool state) {
  //   _lastPage.sink.add(state);
  // }
  void updateModel(MyModel model) {
    _myModel.sink.add(model);
  }

  dispose() {
    _myModel.close();
  }
}

final welcomeBloc = WelcomeBloc();

class ViewerWrapper extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return StreamBuilder<MyModel>(
        stream: welcomeBloc.getModel,
        builder: (context, AsyncSnapshot<MyModel> snapshot) {
          if (snapshot.hasData) {
            MyModel model = snapshot.data;
            return PageView(
              children: <Widget>[
                Page1(),
                Page2(),
                Login(),
              ],
              onPageChanged: (page) {
                model.currentPage = page;
                welcomeBloc.updateModel(model);
                print(model.currentPage);
                // welcomeBloc.updatePage(page + 1);
              },
              controller: model.pageController,
            );
          }
          return Center(child: CircularProgressIndicator());
        });
  }
}

第二个

如果你还需要其他地方的其他流等等,你可以组合流,你可以用任何你想要的方式组合它们,列表,映射,或者定义好的模型,我使用了一个模型(MyModel)。

import 'package:flutter/material.dart';
import 'package:rxdart/rxdart.dart';

class MyModel {
  PageController pageController;
  int currentPage;
  bool isLastPage;

  MyModel({this.currentPage, this.pageController, this.isLastPage});
}

class WelcomeBloc {
  final _controller = PublishSubject<PageController>();
  final _page = PublishSubject<int>();
  final _lastPage = PublishSubject<bool>();

  Stream<MyModel> get combinedStream =>
      Rx.combineLatest3(_page, _lastPage, _controller,
          (int page, bool isLast, PageController controller) {
        return MyModel(
          currentPage: page,
          isLastPage: isLast,
          pageController: controller,
        );
      });

  Stream<PageController> get getController => _controller.stream;
  Stream<int> get currentPage => _page.stream;
  Stream<bool> get isLastPage => _lastPage.stream;

  updatePage(int page) {
    _page.sink.add(page);
  }

  updatePageState(bool state) {
    _lastPage.sink.add(state);
  }

  dispose() {
    _controller.close();
    _page.close();
    _lastPage.close();
  }
}

final welcomeBloc = WelcomeBloc();

class ViewerWrapper extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return StreamBuilder<MyModel>(
        stream: welcomeBloc.combinedStream,
        builder: (context, AsyncSnapshot<MyModel> snapshot) {
          if (snapshot.hasData) {
            MyModel model = snapshot.data;

            return PageView(
              children: <Widget>[
                Page1(),
                Page2(),
                Login(),
              ],
              onPageChanged: (page) {
                welcomeBloc.updatePage(page);
                print(model.currentPage);
                // welcomeBloc.updatePage(page + 1);
              },
              controller: model.pageController,
            );
          }
          return Center(child: CircularProgressIndicator());
        });
  }
}

【讨论】:

  • 如果我没听错的话,这个模型只会将三个流组合在一起,对吧?但是我需要在我的 StreamBuilder/stream 中使用一个相互流。它将无法订阅它。当你在一个集团中有几个流时你会怎么做?
  • 对不起,如果我的问题看起来太傻了)但我在这里有点困惑
  • 不,它不结合 3 个流,它将这些信息组合在一个模型中,然后在一个流中你可以拥有所有主题。我将编辑我的答案以获取更多详细信息。
  • 非常感谢您的帮助!但是组合流还有另一个问题。 combineTheLatest3 等待所有三个流发出值。在此之前它是空的。但是好的,这可以通过流小部件中的 initState 来解决,但显然 combineLatest3 或任何其他作品(如 zipStream)。我还没有在你的 sn-p 中尝试过,但它在我使用 rxDart 库时确实如此。
  • 是的,这是真的,我想这是第一次它需要所有流都有价值,你可以使用Rx.forkJoin3If an inner observable does not complete forkJoin will never emit a value
【解决方案2】:

不要以为事情就是这样。尽管如果您想这样做,请尝试将您的流构建器作为另一个流构建器的子级。但我不会推荐这种方式。

您不会收听来自同一个 bloc 的多个流,一个好方法是每个 bloc 架构有一个流。

您可以阅读有关提供程序的更多信息,它们比 bloc 更简单,并且受到 Flutter 社区的推荐。

【讨论】:

  • 我在玩各种模式和数据管理系统,比如 Provider、Redux 和 Bloc + Streams。我完全同意你关于提供者的看法。我喜欢它,它真的很简单。但是 Providers 不能与 Streams 一起使用,而且由于我使用过 Angular 并且都是关于流的,所以我也想尝试这种方式。最好了解几种方法来满足您的需求。很多人推荐 Bloc,所以我想这一定是有原因的。到目前为止,我可以看到它对构建架构很有好处。但是让我感到困惑的是,你只能在那里使用一个流
  • 也许如果您有几分钟的时间,您也可以快速浏览一下这些问题吗? ;) Flutter 社区在这里不是那么健谈 :D - stackoverflow.com/questions/61598767/…
猜你喜欢
  • 2019-05-23
  • 2020-07-24
  • 2019-04-02
  • 2021-02-12
  • 2021-03-26
  • 1970-01-01
  • 1970-01-01
  • 2019-04-16
  • 2020-03-20
相关资源
最近更新 更多