【发布时间】:2020-12-17 19:53:44
【问题描述】:
今天我遇到了流和 StreamBuilder 的问题。 问题如下: 如果您有多个 StreamBuilder 小部件侦听同一个流,并且您将数据添加到其接收器中,则此数据将通过您拥有的 StreamBuilder 侦听器的数量从流中流出,换句话说: 如果您有一个 StreamController(或 BehaviorSubject),k 个 StreamBuilder 类型的小部件,并且您尝试执行 StreamController.sink.add(event),则此事件将通过流发出 k 次,每个 StreamBuilder 一个。 这是一种预期的行为(预期的行为=输入一个事件并从另一端只听一次,与听众的数量无关)?我能够“修复”这个将几乎所有小部件树封装到一个 StreamBuilder 中的问题,但这并不像第一种方法那样最佳,因为您正在渲染整个树而不是一些小节点小部件。 这里我留下了一些代码来测试它,如果你愿意的话(这个代码是对 flutter create project_name 项目的修改)。 谢谢! (PD:如果您只收听没有 StreamBuilder 的流,这很有效,即:streamController.stream.listen..)
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:rxdart/subjects.dart';
class MyAppBloc with ChangeNotifier {
int _currentIndex;
BehaviorSubject<bool> _controller;
MyAppBloc() {
_currentIndex = 0;
_controller = BehaviorSubject<bool>();
}
Stream<int> get currentIndex => _controller.stream.map<int>((event) {
print('[event: $event]');
_currentIndex++;
return _currentIndex;
});
StreamSink<bool> get increment => _controller.sink;
void close() {
_controller.close();
}
}
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_project/bloc/my_app_bloc.dart';
class MyHomePage extends StatelessWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
Widget leadingBuilder(MyAppBloc bloc) {
return StreamBuilder<int>(
initialData: 0,
stream: bloc.currentIndex,
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
print('[leadingBuilderSnapshot: $snapshot]');
return Text(snapshot.data.toString());
},
);
}
StreamBuilder<int> counterBuilder(MyAppBloc bloc) {
return StreamBuilder<int>(
initialData: 0,
stream: bloc.currentIndex,
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
print('[counterBuilderSnapshot: $snapshot]');
return Text(
snapshot.data.toString(),
style: Theme.of(context).textTheme.headline4,
);
},
);
}
@override
Widget build(BuildContext context) {
print('[build]');
final _bloc = Provider.of<MyAppBloc>(context);
return Scaffold(
appBar: AppBar(
leading: Container(
width: 30,
height: 30,
alignment: Alignment.center,
child: leadingBuilder(_bloc),
),
title: Text(title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
StreamBuilder<int>(
initialData: 0,
stream: _bloc.currentIndex,
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
return Text('${snapshot.data}');
},
),
Text(
'You have pushed the button this many times:',
),
counterBuilder(_bloc),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => _bloc.increment.add(true),
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
【问题讨论】:
-
我不明白您的问题/解释,您输入了数字 1 并在每个流构建器中收到了不同的数字(因为您正在流内进行增量,并且发生这种情况是合乎逻辑的)或者您预计会在所有流构建器中获得第一名?
-
我只是将 true 添加到接收器以触发增量事件,我从 0 开始,当我收到将其显示到视图中的状态时,它显示 2,然后是 4,然后...就像它在索引中增加了两个,我不明白为什么会这样,因为我只是向接收器添加一个事件,它应该输出一个状态,因此会增加一个,不是吗?
-
发生这种情况是因为增量在streambuilder的get中,所以每次调用增量都会执行。与其调用接收器,不如调用块中的一个函数,将其递增并将其添加到接收器。
-
是的,该解决方法工作正常,但我不明白为什么如果我只向接收器添加一个事件,在这种情况下它会被处理两次。我想象的流程是添加一个事件、处理数据并在每个侦听器中侦听该单个状态,但这种行为就像我为每个侦听器添加一个事件
-
您在流构建器的 get 中添加了增量,因此每次流构建器收到要更新的指令时,他都会获取流(他获取流)然后增量发生.. 如果您有 n 个流构建器,他会做 n 次获取和 n 次递增。
标签: flutter stream duplicates stream-builder sink