加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

architecture – Flutter嵌套的StreamBuilders导致Bad状态:Stre

发布时间:2020-12-14 14:58:06 所属栏目:百科 来源:网络整理
导读:我正在尝试使用视频 Flutter / AngularDart – Code sharing,better together (DartConf 2018)中描述的BLoC模式构建Flutter应用程序 BLoC基本上是一个带有Sink输入和Stream输出的视图模型.在我的例子中它看起来有点像这样: class BLoC { // inputs SinkStri
我正在尝试使用视频 Flutter / AngularDart – Code sharing,better together (DartConf 2018)中描述的BLoC模式构建Flutter应用程序

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

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

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

我在层次结构根目录附近的小部件中定义了BLoC,并将其传递给它下面的小部件,包括嵌套的StreamBuilders.像这样:

BLoC widget hierarchy

顶级StreamBuilder监听BLoC上的showLoading流,以便它可以重建以显示重叠的进度微调器.底部StreamBuilder侦听submitEnabled流以启用/禁用按钮.

问题是每当showLoading流导致顶级StreamBuilder重建窗口小部件时,它也会重建嵌套窗口小部件.这本身就很好并且预期.但是,这会导致重新创建底部的StreamBuilder.当发生这种情况时,它会尝试重新订阅BLoC上的现有submitEnabled流,从而导致Bad状态:Stream已被监听

有没有办法在不创建所有输出BroadcastStream的情况下完成此操作?

(我也有可能从根本上误解BLoC模式.)

下面的实际代码示例:

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();
  }
}

解决方法

据我了解BLoC,您应该只有一个输出流连接到StreamBuilder.此输出流发出包含所有必需状态的模型.

你可以在这里看到它是如何完成的:https://github.com/ReactiveX/rxdart/blob/master/example/flutter/github_search/lib/github_search_widget.dart

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读