gpt4 book ai didi

architecture - flutter 嵌套的 StreamBuilders 导致错误状态 : Stream has already been listened to

转载 作者:IT老高 更新时间:2023-10-28 12:31:21 26 4
gpt4 key购买 nike

我正在尝试使用视频 Flutter / AngularDart – Code sharing, better together (DartConf 2018) 中描述的 BLoC 模式构建 Flutter 应用程序

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

 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 state: Stream has been listened

有没有什么方法可以在不使所有输出 BroadcastStreams 的情况下实现这一点?

(我也有可能从根本上误解了 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

新链接: https://github.com/ReactiveX/rxdart/blob/master/example/flutter/github_search/lib/search_widget.dart

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

关于architecture - flutter 嵌套的 StreamBuilders 导致错误状态 : Stream has already been listened to,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49764061/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com