Closed gerryau closed 4 years ago
Hi @gerryau 👋 Thanks for opening an issue!
Can you please provide a link to a sample app which reproduces the issue? Thanks 🙏
Hey @felangel thanks for your reply, I've just invited you to see the app, where the problem exists. It's under the todo-timer branch. Thanks
Hi @gerryau I am unable to run due to a missing GoogleService-Info.plist. Would it be possible for you to put together a simple sample app which ideally doesn't have a Firebase dependency and reproduces the issue? It would be much easier for me to help if I can easily reproduce the issue locally, thanks!
No problem @felangel , see link: https://github.com/gerryau/todo-bloc
Hey @gerryau 👋
I took a look and the issue is there is a frame where the TodoTimerState
is TodoTimerState.initial()
which means that when you call state.todo.name.getOrCrash()
it will crash since the todo is empty. This is because the bloc's initial state is TodoTimerState.initial()
and when you add the TodoTimerEvent.initialized
event it still takes a frame to propagate so the TimerFormScaffold
will be rendered at least once where the state has not been updated.
I opened a pull request with one potential fix. Hope that helps!
Closing for now but feel free to comment with additional questions and I'm happy to continue the conversation 👍
Hello, sorry for writing here, but I encountered this problem on my project as well and it's been a week and I could not fix the problem.
How did you managed to fix this issue ? . @gerryau
@felangel I understand the cause, but I tried in several ways to solve it and with no success. Can you help me with this issue ?
My project is: https://github.com/gizet/vault_pass
Class where the exception is thrown: AccountView. When I check my debug in the BlocObserver the the state changes correctly but when it reaches the BlocBuilder the initial value is taken into account and not the newly changed state with the initialized values.
Issue:
Stacktrace:
======== Exception caught by widgets library =======================================================
The following UnexpectedValueError was thrown building BlocBuilder<RecordBloc, RecordState>(dirty, dependencies: [_InheritedProviderScope<RecordBloc?>], state: _BlocBuilderBaseState<RecordBloc, RecordState>#77787):
"Encountered a Error at an unrecoverable point. Failure was: MicroTypeFailure<String>.invalidString(failedValue: )"
The relevant error-causing widget was:
BlocBuilder<RecordBloc, RecordState> BlocBuilder:file:///D:/_workspace/flutter/vault_pass/lib/presentation/view/records/account/account_view.dart:37:12
When the exception was thrown, this was the stack:
#0 MicroType.get.<anonymous closure> (package:vault_pass/domain/microtypes/microtype.dart:15:30)
#1 Left.match (package:fpdart/src/either.dart:592:72)
#2 Either.fold (package:fpdart/src/either.dart:255:7)
#3 MicroType.get (package:vault_pass/domain/microtypes/microtype.dart:15:18)
#4 _AccountViewState.build.<anonymous closure> (package:vault_pass/presentation/view/records/account/account_view.dart:64:83)
#5 BlocBuilder.build (package:flutter_bloc/src/bloc_builder.dart:90:57)
#6 _BlocBuilderBaseState.build (package:flutter_bloc/src/bloc_builder.dart:166:21)
#7 StatefulElement.build (package:flutter/src/widgets/framework.dart:5080:27)
#8 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4968:15)
#9 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5133:11)
#10 Element.rebuild (package:flutter/src/widgets/framework.dart:4690:5)
#11 StatefulElement.update (package:flutter/src/widgets/framework.dart:5156:5)
#12 Element.updateChild (package:flutter/src/widgets/framework.dart:3660:15)
#13 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4993:16)
#14 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5133:11)
#15 Element.rebuild (package:flutter/src/widgets/framework.dart:4690:5)
#16 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2743:19)
#17 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:863:21)
#18 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:381:5)
#19 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1289:15)
#20 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1218:9)
#21 SchedulerBinding.scheduleWarmUpFrame.<anonymous closure> (package:flutter/src/scheduler/binding.dart:942:7)
#25 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:192:26)
(elided 3 frames from class _Timer and dart:async-patch)
====================================================================================================
Reloaded 2 of 1556 libraries in 1,742ms (compile: 40 ms, reload: 338 ms, reassemble: 1243 ms).
D/EGL_emulation( 6445): app_time_stats: avg=53314.34ms min=53314.34ms max=53314.34ms count=1
Describe the bug Error saying string value of a bloc state is empty, but the desired result is achieved on device when running.
Expected behavior No error.
════════ Exception caught by widgets library ═══════════════════════════════════ The following UnexpectedValueError was thrown building BlocBuilder<TodoTimerBlockFormBloc, TodoTimerBlockFormState>(dirty, state: _BlocBuilderBaseState<TodoTimerBlockFormBloc, TodoTimerBlockFormState>#f5386): "Encountered a ValueFailure at an unrecoverable point. Terminating. Failure was: ValueFailure.empty(failedValue: )"
The relevant error-causing widget was BlocBuilder<TodoTimerBlockFormBloc, TodoTimerBlockFormState> package:app/…/todo_timer_form/new_todo_timer_form_page.dart:69 When the exception was thrown, this was the stack
0 ValueObject.getOrCrash.
package:app/…/core/value_objects.dart:21
1 Left.fold
package:dartz/src/either.dart:124
2 ValueObject.getOrCrash
package:app/…/core/value_objects.dart:21
3 TimerFormScaffold.build.
package:app/…/todo_timer_form/new_todo_timer_form_page.dart:71
4 BlocBuilder.build
package:flutter_bloc/src/bloc_builder.dart:90 ... ════════════════════════════════════════════════════════════════════════════════
@injectable class TodoTimerBlockFormBloc extends Bloc<TodoTimerBlockFormEvent, TodoTimerBlockFormState> { final ITodoRepository _todoRepository;
TodoTimerBlockFormBloc(this._todoRepository);
@override TodoTimerBlockFormState get initialState => TodoTimerBlockFormState.initial();
@override Stream mapEventToState(
TodoTimerBlockFormEvent event,
) async {
yield event.map(
initialized: (e) async* {
yield e.initialTodoOption.fold(
() => state,
(initialTodo) {
return state.copyWith(
todo: initialTodo,
);
},
);
},
...
class NewTimerPage extends HookWidget { final TodoItem selectedTodo;
const NewTimerPage({ Key key, @required this.selectedTodo, }) : super(key: key);
@override Widget build(BuildContext context) { return BlocProvider(
create: (context) => getIt()
..add(TodoTimerBlockFormEvent.initialized(optionOf(selectedTodo))),
child: BlocConsumer<TodoTimerBlockFormBloc, TodoTimerBlockFormState>(
listener: (context, state) {
...
builder: (context, state) {
return Stack(
children: [
TimerFormScaffold(),
],
);
}
),
);
}
}
class TimerFormScaffold extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: BlocBuilder<TodoTimerBlockFormBloc, TodoTimerBlockFormState>( builder: (context, state){ return Text(state.todo.name.getOrCrash()); }, ) ), ); } }