Bloc: Initial State not loading correctly

Created on 7 Aug 2020  ยท  6Comments  ยท  Source: felangel/bloc

Describe the bug
For my project I need to load measurements based on a date. On the diary page the initial date should be DateTime.now(). This is actually the same functionality as filtered_todos.
I use in my project Firebase with a Stream Subscription. After upgrading flutter_bloc to the lates release the initial state is broken, and I am not able to load the initial date. Instead it loads all the measurements instead of the measurement for that date.

Also the state is mixed up when I go back to the diary screen after filtering the date in a previous action. Than the state loads the date of before.

To Reproduce
My Code:
```import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:diabetes/src/blocs/logbook/logbook.dart';
import 'package:diabetes/src/blocs/measurements/measurements.dart';
import 'package:diabetes/src/model/measurement.dart';
import 'package:intl/intl.dart';
import 'package:meta/meta.dart';

class LogbookBloc extends Bloc {
final MeasurementsBloc _measurementsBloc;
StreamSubscription _measurementsSubscription;

LogbookBloc({@required MeasurementsBloc measurementsBloc})
: assert(measurementsBloc != null),
_measurementsBloc = measurementsBloc,
super(measurementsBloc.state is MeasurementsLoaded
? LogbookLoaded(
(measurementsBloc.state as MeasurementsLoaded).measurements,
DateTime.now(),
)
: LogbookLoading()) {
_measurementsSubscription = measurementsBloc.listen((state) {
if (state is MeasurementsLoaded) {
add(UpdateLogbook(
(measurementsBloc.state as MeasurementsLoaded).measurements));
}
});
}

@override
Stream mapEventToState(LogbookEvent event) async* {
if (event is UpdateFilter) {
yield* _mapUpdateFilterToState(event);
} else if (event is UpdateLogbook) {
yield* _mapUpdateLogbookToState(event);
}
}

Stream _mapUpdateFilterToState(UpdateFilter event) async* {
final currentState = _measurementsBloc.state;
if (currentState is MeasurementsLoaded) {
yield LogbookLoaded(
_mapMeasurementsToFilteredLogbook(
(_measurementsBloc.state as MeasurementsLoaded).measurements,
event.filter),
event.filter,
);
}
}

Stream _mapUpdateLogbookToState(UpdateLogbook event) async* {
final filteredDate = state is LogbookLoaded
? (state as LogbookLoaded).filteredDate
: DateTime.now();

yield LogbookLoaded(
  _mapMeasurementsToFilteredLogbook(
    (_measurementsBloc.state as MeasurementsLoaded).measurements,
    filteredDate,
  ),
  filteredDate,
);

}

List _mapMeasurementsToFilteredLogbook(
List measurements, DateTime filteredDate) {
measurements.sort((a, b) => a.dateTime.compareTo(b.dateTime));
return measurements
.where((Measurement m) =>
DateFormat('DDMM').format(m.dateTime).toString() ==
DateFormat('DDMM').format(filteredDate).toString())
.toList();
}

@override
Future close() {
_measurementsSubscription?.cancel();
return super.close();
}
}
```

Expected behavior
Load only the measurements of today when loading the first time.

Screenshots

*Logs *
This is the output when I print filtered Date and Mesurements.

flutter: Filtered Date: 2020-08-07 14:26:57.465564 flutter: Measurements [Measurement{id: 3scj11rb9vzJVsuvVhWx,result: 8.0, resultMg: null, resultMmol: null, resultCups: null, resultMl: null, resultOz: null, resultKg: null, resultLbs: null, uom: mmol, dayTime: After Lunch, dateTime: 2020-06-06 11:46:13.543, type: glucose,comment: fdf}, Measurement{id: IKuvEaNuYzWupXgzU4ll,result: 12.0, resultMg: 216.0, resultMmol: 12.0, resultCups: null, resultMl: null, resultOz: null, resultKg: null, resultLbs: null, uom: mmol, dayTime: After Lunch, dateTime: 2020-08-04 10:09:33.467, type: glucose,comment: }, Measurement{id: rvk0izvSaYmDLhnVx52Q,result: 55.1, resultMg: null, resultMmol: null, resultCups: null, resultMl: null, resultOz: null, resultKg: null, resultLbs: null, uom: mmol, dayTime: Before Lunch, dateTime: 2020-07-19 18:46:37.885999, type: glucose,comment: Fgfgf}, Measurement{id: xQMrlqQ6r0zc1cCGaNU3,result: 2.0, resultMg: null, resultMmol: null, resultCups: 2.0, resultMl: 473.0, resultOz: 16.0, resultKg: null, resultLbs: null, uom: cups, dayTime: o<โ€ฆ>

Additional context
Add any other context about the problem here.

question

All 6 comments

Hi @reijerteunis ๐Ÿ‘‹

Current state of the bloc is not emitted upon listening anymore so you should do:
_measurementsSubscription = measurementsBloc.startWith(measurementsBloc.state).listen(...).

This would give you the previous functionality.

startWith comes from rxdart package.

Hi @RollyPeres ๐Ÿค

Great it almost worked. 1 issue left:

When I go to the page I have the correct result:

image

When I than go to another date I see those results:
image

Than when I navigate to another screen and come back to the diary again, I get the wrong results:
image

By the way I think the same issue is in flutter_todo within the example modules (the firebase version)

Did you debug it to follow what's going on ? Are you logging the transitions on your bloc ?
If you can't solve it feel free to post a repo with a minimal reproduction of your issue and I'll have a look.

Thanks will first dive into it and if I can't find it I will reach out to you ๐Ÿ™‡

Really appreciated the help

Closing for now but feel free to comment with additional questions/comments and I'm happy to continue the conversation ๐Ÿ‘

I have faced a similar issue and solved it by following your suggestion:

Hi @reijerteunis ๐Ÿ‘‹

Current state of the bloc is not emitted upon listening anymore so you should do:
_measurementsSubscription = measurementsBloc.startWith(measurementsBloc.state).listen(...).

This would give you the previous functionality.

startWith comes from rxdart package.

but now, I have faced error coding the test part. It seems that bloc_test does not recognize startWith method and returns
NoSuchMethodError: The method 'listen' was called on null. error

Was this page helpful?
0 / 5 - 0 ratings