Reputation: 16651
I have 2 screens
- Screen A
- Screen B
I go from screen A
to Screen B
via the below code
onTap: () {
Navigator.pushNamed(context, '/screen_b');
},
Screen B code
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());
},
....
}
}
When i click tap to add CreateSampleEvent
to the sampleBloc
in Screen B, the 'sampleBloc.stream.listen' getting fired multiples times.
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();
}
}
Any ideas what might be going wrong ?
Upvotes: 1
Views: 4801
Reputation: 17746
Since you are creating a manual subscription (by fetching the Bloc and then listening to a stream
) you'll also need to manually cancel that subscription when you're done with it, otherwise, the SampleBloc
will just keep getting new subscriptions and yielding events to all of them.
For that, you can either:
dispose()
method. 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
from the package which is a widget that is disposed automatically, hence, removes the subscriptions it created.BlocListener<BlocA, BlocAState>(
listener: (context, state) {
// do stuff here based on BlocA's state
},
child: Container(),
)
Upvotes: 2