Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/dart/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Architecture 颤振嵌套StreamBuilders导致错误状态:流已被侦听_Architecture_Dart_Flutter - Fatal编程技术网

Architecture 颤振嵌套StreamBuilders导致错误状态:流已被侦听

Architecture 颤振嵌套StreamBuilders导致错误状态:流已被侦听,architecture,dart,flutter,Architecture,Dart,Flutter,我正在尝试使用视频中描述的BLoC模式构建一个flatter应用程序 BLoC基本上是一个视图模型,具有Sink输入和Stream输出。在我的示例中,它看起来有点像这样: class BLoC { // inputs Sink<String> inputTextChanges; Sink<Null> submitButtonClicks; // outputs Stream<bool> showLoading;

我正在尝试使用视频中描述的BLoC模式构建一个flatter应用程序

BLoC基本上是一个视图模型,具有
Sink
输入和
Stream
输出。在我的示例中,它看起来有点像这样:

 class BLoC {
    // inputs
    Sink<String> inputTextChanges;
    Sink<Null> submitButtonClicks;

    // outputs
    Stream<bool> showLoading;
    Stream<bool> submitEnabled;
 }

正如我对BLoC的理解,您应该只有一个连接到StreamBuilder的输出流。此输出流发出一个包含所有必需状态的模型

你可以在这里看到它是如何完成的:

新链接:


如果需要组合多个流来生成模型(sowLoading和submitEnabled),可以使用RxDart中的
Observable.combinelateTest
将多个流合并为一个流。我使用这种方法,效果非常好。

使用BehaviorSubject而不是StreamController.BehaviorSubject会将最近的事件发送给消费者

我看过这个示例,非常好,但是,它与视频中描述的模式不同,因为它只有一个包含整个状态模型的输出流。视频中的BLoC模式有多个可独立订阅的输出流,这就是我喜欢它的地方。否则,我可能会使用Redux之类的东西。遗憾的是,URL不再可用。对单个事件源使用多个流是不正确的,只需使用广播流即可。从概念上讲,每个源没有多个观察者。同一个观察者被重建并需要重新订阅这一事实是颤振实现的细节。如果UI是用类似Angular的东西构建的,则可能不会发生这种情况。但是如果说所有的输出都是广播流,可能有多个观察者,有没有副作用?StreamBuilder是否在其流被销毁和重建时取消订阅?这可能会有所帮助看起来您的问题可能是“是否可以将多个流传递给StreamBuilder?”。问题是你的例子很简单。如果我需要监听两个以上的流,我不知道该怎么办,例如,我想监听请求、错误和结果对象的网络状态。我认为它应该类似于
流:[bloc.isLoading,bloc.errors,bloc.user]
。因为组件的
StreamBuilder
嵌套包装看起来非常混乱。
import 'package:flutter/material.dart';
import 'package:rxdart/rxdart.dart';
import 'dart:async';

void main() => runApp(BlocExampleApp());

class BlocExampleApp extends StatefulWidget {

  BlocExampleApp({Key key}) : super(key: key);

  @override
  _BlocExampleAppState createState() => _BlocExampleAppState();
}

class _BlocExampleAppState extends State<BlocExampleApp> {

  Bloc bloc = Bloc();

  @override
  Widget build(BuildContext context) =>
      MaterialApp(
        home: Scaffold(
            appBar: AppBar(elevation: 0.0),
            body: new StreamBuilder<bool>(
                stream: bloc.showLoading,
                builder: (context, snapshot) =>
                snapshot.data
                    ? _overlayLoadingWidget(_buildContent(context))
                    : _buildContent(context)
            )
        ),
      );

  Widget _buildContent(context) =>
      Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            TextField(
              onChanged: bloc.inputTextChanges.add,
            ),
            StreamBuilder<bool>(
                stream: bloc.submitEnabled,
                builder: ((context, snapshot) =>
                    MaterialButton(
                      onPressed: snapshot.data ? () => bloc.submitClicks.add(null) : null,
                      child: Text('Submit'),
                    )
                )
            )
          ]
      );

  Widget _overlayLoadingWidget(Widget content) =>
      Stack(
        children: <Widget>[
          content,
          Container(
            color: Colors.black54,
          ),
          Center(child: CircularProgressIndicator()),
        ],
      );
}

class Bloc {
  final StreamController<String> _inputTextChanges = StreamController<String>();
  final StreamController<Null> _submitClicks = StreamController();

  // Inputs
  Sink<String> get inputTextChanges => _inputTextChanges.sink;

  Sink<Null> get submitClicks => _submitClicks.sink;

  // Outputs
  Stream<bool> get submitEnabled =>
      Observable<String>(_inputTextChanges.stream)
          .distinct()
          .map(_isInputValid);

  Stream<bool> get showLoading => _submitClicks.stream.map((_) => true);

  bool _isInputValid(String input) => true;

  void dispose() {
    _inputTextChanges.close();
    _submitClicks.close();
  }
}