Bloc 要么多次调用,要么根本没有被调用
Bloc is either calling multiple times or not getting called at all
我有 2 个屏幕
- Screen A
- Screen B
我通过以下代码从 screen A
转到 Screen B
onTap: () {
Navigator.pushNamed(context, '/screen_b');
},
屏幕B码
class ScreenB extends StatefulWidget {
@override
_ScreenBState createState() => _ScreenBState();
}
class _ScreenBState extends State<ScreenB> {
SampleBloc sampleBloc;
@override
void initState() {
super.initState();
sampleBloc = BlocProvider.of<SampleBloc>(context);
sampleBloc.stream.listen((state) {
// this is getting called multiple times.
}
}
@override
void dispose() {
super.dispose();
sampleBloc.clear(); // If i add this, no event is firing from second time i come to the page. initState() is being called i checked so sampleBloc is not null.
}
@override
Widget build(BuildContext context) {
....
onTap: () {
sampleBloc.add(CreateSampleEvent());
},
....
}
}
当我点击点击将 CreateSampleEvent
添加到屏幕 B 中的 sampleBloc
时,'sampleBloc.stream.listen' 被触发多次。
Sample outcome
Step 1. First do sampleBloc.add (tap)
-> sampleBloc.stream.listen
fired one time
Step 2. Go back to Screen A and come back to
Screen B Second go sampleBloc.add (tap)
-> In one case i saw
the firing takes place in a pair of 2 times, and in other times the
firing takes place in pair of 4 times.
class SampleBloc extends Bloc<SampleEvent, SampleState> {
final SampleRepository sampleRepository;
SampleBloc({this.sampleRespository}) : super(null);
@override
Stream<SampleState> mapEventToState(SampleEvent event) async* {
if (event is SampleEvent) {
yield* mapSampleEventToState();
}
}
Stream<SampleEvent> mapSampleEventToState() async* {
yield SampleInProgressState();
try {
String sampleId = await sampleRepository.createSample();
if (sampleId != null) {
yield SampleCompletedState(sampleId, uid);
} else {
yield SampleFailedState();
}
} catch (e) {
print('Error: $e');
yield SampleFailedState();
}
}
知道可能出了什么问题吗?
由于您正在创建手动订阅(通过获取 Bloc 然后收听 stream
),因此您还需要手动取消 该订阅,当您完成它,否则,SampleBloc
将继续获取新订阅并为所有订阅生成事件。
为此,您可以:
- 保存订阅,然后在
dispose()
方法中取消。
SampleBloc sampleBloc;
StreamSubscription _subscription;
@override
void initState() {
super.initState();
sampleBloc = BlocProvider.of<SampleBloc>(context);
_subscription = sampleBloc.stream.listen((state) {
// this is getting called multiple times.
}
}
@override
void dispose() {
_subscription.cancel();
super.dispose();
}
- 您可以利用包中的
BlocListener
,这是一个自动处理的小部件,因此删除它创建的订阅。
BlocListener<BlocA, BlocAState>(
listener: (context, state) {
// do stuff here based on BlocA's state
},
child: Container(),
)
我有 2 个屏幕
- Screen A
- Screen B
我通过以下代码从 screen A
转到 Screen B
onTap: () {
Navigator.pushNamed(context, '/screen_b');
},
屏幕B码
class ScreenB extends StatefulWidget {
@override
_ScreenBState createState() => _ScreenBState();
}
class _ScreenBState extends State<ScreenB> {
SampleBloc sampleBloc;
@override
void initState() {
super.initState();
sampleBloc = BlocProvider.of<SampleBloc>(context);
sampleBloc.stream.listen((state) {
// this is getting called multiple times.
}
}
@override
void dispose() {
super.dispose();
sampleBloc.clear(); // If i add this, no event is firing from second time i come to the page. initState() is being called i checked so sampleBloc is not null.
}
@override
Widget build(BuildContext context) {
....
onTap: () {
sampleBloc.add(CreateSampleEvent());
},
....
}
}
当我点击点击将 CreateSampleEvent
添加到屏幕 B 中的 sampleBloc
时,'sampleBloc.stream.listen' 被触发多次。
Sample outcome
Step 1. First do
sampleBloc.add (tap)
-> sampleBloc.stream.listen fired one time
Step 2. Go back to Screen A and come back to Screen B Second gosampleBloc.add (tap)
-> In one case i saw the firing takes place in a pair of 2 times, and in other times the firing takes place in pair of 4 times.
class SampleBloc extends Bloc<SampleEvent, SampleState> {
final SampleRepository sampleRepository;
SampleBloc({this.sampleRespository}) : super(null);
@override
Stream<SampleState> mapEventToState(SampleEvent event) async* {
if (event is SampleEvent) {
yield* mapSampleEventToState();
}
}
Stream<SampleEvent> mapSampleEventToState() async* {
yield SampleInProgressState();
try {
String sampleId = await sampleRepository.createSample();
if (sampleId != null) {
yield SampleCompletedState(sampleId, uid);
} else {
yield SampleFailedState();
}
} catch (e) {
print('Error: $e');
yield SampleFailedState();
}
}
知道可能出了什么问题吗?
由于您正在创建手动订阅(通过获取 Bloc 然后收听 stream
),因此您还需要手动取消 该订阅,当您完成它,否则,SampleBloc
将继续获取新订阅并为所有订阅生成事件。
为此,您可以:
- 保存订阅,然后在
dispose()
方法中取消。
SampleBloc sampleBloc;
StreamSubscription _subscription;
@override
void initState() {
super.initState();
sampleBloc = BlocProvider.of<SampleBloc>(context);
_subscription = sampleBloc.stream.listen((state) {
// this is getting called multiple times.
}
}
@override
void dispose() {
_subscription.cancel();
super.dispose();
}
- 您可以利用包中的
BlocListener
,这是一个自动处理的小部件,因此删除它创建的订阅。
BlocListener<BlocA, BlocAState>(
listener: (context, state) {
// do stuff here based on BlocA's state
},
child: Container(),
)