Объединение потоков в блок

У меня в блоке несколько стримов. Я не уверен, что это правильный и правильный подход, потому что я новичок в шаблоне Flutter и 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,
          );
        });
  }
}


person Valary o    schedule 06.05.2020    source источник
comment
что вы имеете в виду под слиянием?   -  person Anirudh Bagri    schedule 06.05.2020
comment
@AnirudhBagri Спасибо, что был здесь, чувак!) Я имею в виду, что в моем файле Bloc у меня есть три потока, но в StreamBuilder я могу подписаться только на один поток. Итак, насколько я понимаю, я должен объединить их вместе, чтобы использовать его в моем StreamBuilder. Я пробовал использовать комбинированный последний, но он мне возвращает ноль. Думаю, я что-то не так делаю.   -  person Valary o    schedule 06.05.2020


Ответы (2)


Вы можете использовать Rx.combineLatest3 Like 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());
        });
  }
}

person NoobN3rd    schedule 06.05.2020
comment
Если я вас понял, эта модель просто объединит три потока вместе, верно? Но мне понадобится общий поток для использования в моем StreamBuilder / stream. Он не сможет подписаться на него. Что вы делаете, когда у вас есть пара потоков в блоке? - person Valary o; 07.05.2020
comment
Извините, если мои вопросы кажутся слишком глупыми) но я немного озадачен здесь - person Valary o; 07.05.2020
comment
Нет, он не объединяет 3 потока, он группирует эту информацию в одну модель, а затем внутри одного потока вы можете иметь все темы. Я отредактирую свой ответ, чтобы узнать подробности. - person NoobN3rd; 07.05.2020
comment
Спасибо большое за вашу помощь! Но есть еще одна проблема с совмещенным потоком. combTheLatest3 ожидает передачи значения всеми тремя потоками. До этого он нулевой. Но хорошо, это можно решить с помощью initState в потоке Widget, но, по-видимому ,commonLatest3 или любой другой работает как zipStream. Я еще не пробовал это в вашем фрагменте, но это было так, когда я играл с библиотекой rxDart. - person Valary o; 08.05.2020
comment
Я забыл упомянуть в ответе, что для объединения потоков я обычно получаю лучшую производительность, используя BehaviorSubject из-за его характера. (всегда возвращает последнее значение каждому новому / старому подписчику). - person NoobN3rd; 08.05.2020
comment
да, я обычно использую BehaviorSubject в экосистеме JS. Это очень полезно, поскольку излучает начальное значение. Единственная проблема в том, что он сохраняет и передает последнее значение всем подписчикам. Спасибо! Я никогда не использовал оператор forkjoin, возможно, это то, что мне нужно. - person Valary o; 08.05.2020
comment
Можете ли вы бросить взгляд ???? на другие мои вопросы? - person Valary o; 08.05.2020
comment
???? Да, конечно! - person NoobN3rd; 08.05.2020
comment
Можете ли вы взглянуть на другой вопрос?) - stackoverflow .com / questions / 61711139 / - person Valary o; 10.05.2020

Не думайте, что это так. Хотя, если вы хотите сделать это таким образом, попробуйте поместить свой построитель потока как дочерний элемент другого построителя потоков. Но я не буду рекомендовать такой способ.

Вы не слушаете несколько потоков из одного и того же блока, хорошим способом было бы иметь один поток для архитектуры каждого блока.

Вы можете узнать больше о провайдерах, они проще, чем блочные, и рекомендованы сообществом флаттеров.

person Anirudh Bagri    schedule 06.05.2020
comment
Я экспериментирую со всевозможными шаблонами и системами управления данными, такими как Provider, Redux и Bloc + Streams. Полностью согласен с вами насчет Провайдера. Мне это нравится, и это действительно очень просто. Но провайдеры не работают с потоками, и поскольку я работал с Angular, и все дело в потоках, я хотел бы попробовать и этот способ. Лучше знать несколько способов, как достичь того, что вам нужно. Многие люди рекомендовали Bloc, поэтому я думаю, для этого должна быть причина. Пока я вижу, что это хорошо для структурирования архитектуры, но меня сбивает с толку, что вы можете использовать там только один поток - person Valary o; 06.05.2020
comment
Может быть, если у вас есть несколько минут, сможете ли вы бросить взгляд на эти вопросы? ;) Сообщество Flutter здесь не такое разговорчивое: D - stackoverflow.com/questions/61598767/ - person Valary o; 06.05.2020