Joe*_*ski 11 architecture dart flutter
我正在尝试使用视频Flutter/AngularDart中描述的BLoC模式构建一个Flutter应用程序- 代码共享,更好地在一起(DartConf 2018)
BLoC基本上是一个带Sink输入和Stream输出的视图模型.在我的例子中,它看起来有点像这样:
class BLoC {
// inputs
Sink<String> inputTextChanges;
Sink<Null> submitButtonClicks;
// outputs
Stream<bool> showLoading;
Stream<bool> submitEnabled;
}
Run Code Online (Sandbox Code Playgroud)
我在层次结构根目录附近的小部件中定义了BLoC,并将其传递给它下面的小部件,包括嵌套的小部件StreamBuilders.像这样:
顶部StreamBuilder监听showLoadingBLoC上的流,以便它可以重建以显示重叠的进度微调器.底部StreamBuilder侦听submitEnabled流以启用/禁用按钮.
问题是当showLoading流导致top StreamBuilder重建窗口小部件时,它也会重建嵌套窗口小部件.这本身就很好并且预期.然而,这导致底部StreamBuilder被重新创建.当发生这种情况时,它会尝试重新订阅submitEnabledBLoC上的现有流Bad state: Stream has already been listened to
有没有办法在不进行所有输出的情况下实现这一目标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();
}
}
Run Code Online (Sandbox Code Playgroud)
据我了解 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),您可以使用Observable.combineLatestRxDart 将多个流合并为一个流。我使用这种方法并且效果非常好。
| 归档时间: |
|
| 查看次数: |
4352 次 |
| 最近记录: |