Flutter MultiProvider: setState() or markNeedsBuild() called during build - flutter

When I do this:
import 'package:blogs/common/theme.dart';
import 'package:blogs/screen/home.dart';
import 'package:blogs/state/authstate.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() => runApp(
MultiProvider(
providers: [ChangeNotifierProvider(create: (context) => AuthState())],
child: const MyApp(),
)
);
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
var authState = context.watch<AuthState>();
if (authState.idToken == null) {
authState.signInWithAutoCodeExchange();
}
return MaterialApp(
title: 'Blogs',
theme: appTheme,
initialRoute: '/',
routes: {'/': (context) => const Home()},
);
}
}
I'm getting
======== Exception caught by foundation library ====================================================
The following assertion was thrown while dispatching notifications for AuthState:
setState() or markNeedsBuild() called during build.
This _InheritedProviderScope<AuthState?> widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
The widget on which setState() or markNeedsBuild() was called was: _InheritedProviderScope<AuthState?>
value: Instance of 'AuthState'
listening to value
The widget which was currently being built when the offending call was made was: MyApp
dirty
dependencies: [_InheritedProviderScope<AuthState?>]
When the exception was thrown, this was the stack:
#0 Element.markNeedsBuild.<anonymous closure> (package:flutter/src/widgets/framework.dart:4424:11)
#1 Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:4439:6)
#2 _InheritedProviderScopeElement.markNeedsNotifyDependents (package:provider/src/inherited_provider.dart:570:5)
#3 ChangeNotifier.notifyListeners (package:flutter/src/foundation/change_notifier.dart:308:24)
#4 AuthState.isBusy= (package:blogs/state/authstate.dart:20:5)
#5 AuthState.setBusyState (package:blogs/state/authstate.dart:210:5)
#6 AuthState.signInWithAutoCodeExchange (package:blogs/state/authstate.dart:175:7)
#7 MyApp.build (package:blogs/main.dart:21:17)
#8 StatelessElement.build (package:flutter/src/widgets/framework.dart:4827:28)
#9 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4754:15)
#10 Element.rebuild (package:flutter/src/widgets/framework.dart:4477:5)
#11 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4735:5)
#12 ComponentElement.mount (package:flutter/src/widgets/framework.dart:4729:5)
#13 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3790:14)
#14 Element.updateChild (package:flutter/src/widgets/framework.dart:3540:18)
#15 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4780:16)
#16 _InheritedProviderScopeElement.performRebuild (package:provider/src/inherited_provider.dart:495:11)
#17 Element.rebuild (package:flutter/src/widgets/framework.dart:4477:5)
#18 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4735:5)
#19 ComponentElement.mount (package:flutter/src/widgets/framework.dart:4729:5)
#20 _InheritedProviderScopeElement.mount (package:provider/src/inherited_provider.dart:395:11)
... Normal element mounting (7 frames)
#27 SingleChildWidgetElementMixin.mount (package:nested/nested.dart:222:11)
... Normal element mounting (7 frames)
#34 _NestedHookElement.mount (package:nested/nested.dart:187:11)
... Normal element mounting (7 frames)
#41 SingleChildWidgetElementMixin.mount (package:nested/nested.dart:222:11)
#42 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3790:14)
#43 Element.updateChild (package:flutter/src/widgets/framework.dart:3540:18)
#44 RenderObjectToWidgetElement._rebuild (package:flutter/src/widgets/binding.dart:1198:16)
#45 RenderObjectToWidgetElement.mount (package:flutter/src/widgets/binding.dart:1167:5)
#46 RenderObjectToWidgetAdapter.attachToRenderTree.<anonymous closure> (package:flutter/src/widgets/binding.dart:1112:18)
#47 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2600:19)
#48 RenderObjectToWidgetAdapter.attachToRenderTree (package:flutter/src/widgets/binding.dart:1111:13)
#49 WidgetsBinding.attachRootWidget (package:flutter/src/widgets/binding.dart:944:7)
#50 WidgetsBinding.scheduleAttachRootWidget.<anonymous closure> (package:flutter/src/widgets/binding.dart:924:7)
(elided 11 frames from class _RawReceivePortImpl, class _Timer, dart:async, and dart:async-patch)
The AuthState sending notification was: Instance of 'AuthState'
====================================================================================================
But when I do this:
import 'package:blogs/common/theme.dart';
import 'package:blogs/screen/home.dart';
import 'package:blogs/state/authstate.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [ChangeNotifierProvider(create: (context) => AuthState())],
child: MaterialApp(
title: 'Blogs',
theme: appTheme,
initialRoute: '/',
routes: {'/': (context) => const Home()},
),
);
}
}
I can't have
var authState = context.watch<AuthState>();
if (authState.idToken == null) {
authState.signInWithAutoCodeExchange();
}
in there before the 1st route is invoked.
However the app starts and runs normally, as the error output states, "exception is allowed".
As I have now found out the culprit is
if (authState.idToken == null) {
authState.signInWithAutoCodeExchange();
}
I'm guessing the state is accessed before building is finished.
I'm thinking maybe wrap it all in a widget, but I need to somehow make sure that building has finished before the state is accessed. How do I make sure that's the case?
I believe this is just not the correct way to approach this problem.
Is there a better or more elegant solution to require the user to be authenticated?

I think this error happens because you tried to call context before flutter has finished building the widget tree.
use this for flutter to execute your code after flutter has finished building the widget.
WidgetsBinding.instance.addPostFrameCallback((_) {// your code in here});

Related

I get the error The following _CastError was thrown building _BodyBuilder: type 'Null' is not a subtype of type 'JokeBloc' in type cast

Here is the My App Screen:
import 'package:api_call_sample/Repository/JokeRepository.dart';
import 'package:api_call_sample/bloc/jokeevent.dart';
import 'package:api_call_sample/bloc/jokestate.dart';
import 'package:flutter/material.dart';
import "package:api_call_sample/bloc/jokebloc.dart";
import 'package:flutter_bloc/flutter_bloc.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: BlocProvider(
create: (context) => JokeBloc(
RepositoryProvider.of<JokeRepository>(context),
)..add(LoadJokeEvent()),
child: const HomeScreen()),
);
}
}
Here is the HomeScreen Screen :Getting Error in the Bloc Builder screen
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Joke Api"),
),
**body: Column( children: [**
**BlocBuilder<JokeBloc, JokeState>(builder: (context, state) {**
print(state);
if (state is JokeLoadingState) {
print("Loading state");
return const CircularProgressIndicator();
}
if (state is JokeLoadedState) {
print(state.jokeData.toString());
return ExpansionTile(
title: Text(state.jokeData.setup),
children: [
Container(
margin: const EdgeInsets.all(5.0),
child: Text(state.jokeData.delivery))
],
);
}
if (state is JokeErrorState) {
print("Error state");
return Text(state.error.toString());
}
return Container();
}),
ElevatedButton(
onPressed: () {
BlocProvider.of<JokeBloc>(context).add(LoadJokeEvent());
},
child: const Text('Load More'))
]),
);
}
}
Here is the JokeBloc:
import 'package:bloc/bloc.dart';
import 'jokestate.dart';
import 'jokeevent.dart';
import 'package:api_call_sample/Repository/JokeRepository.dart';
class JokeBloc extends Bloc<JokeEvent,JokeState>{
final JokeRepository _jokeRepository;
JokeBloc(this._jokeRepository) : super(JokeLoadingState())
{
on<LoadJokeEvent>((event, emit) async {
emit(JokeLoadingState());
try {
final joke = await _jokeRepository.getJoke();
emit(JokeLoadedState(joke));
} catch (e) {
emit(JokeErrorState(e.toString()));
}
});
}
}
Error Message :
The following _CastError was thrown building _BodyBuilder:
type 'Null' is not a subtype of type 'JokeBloc' in type cast.
The relevant error-causing widget was:Scaffold Scaffold:file:///Applications/flutter/api_call_sample/lib/main.dart:37:12
The relevant error-causing widget was:
Scaffold Scaffold:file:///Applications/flutter/api_call_sample/lib/main.dart:37:12
When the exception was thrown, this was the stack:
#0 _CreateInheritedProviderState.value (package:provider/src/inherited_provider.dart:786:72)
#1 _CreateInheritedProviderState.debugFillProperties (package:provider/src/inherited_provider.dart:806:44)
#2 _InheritedProviderScopeElement.debugFillProperties (package:provider/src/inherited_provider.dart:631:20)
#3 DiagnosticableNode.builder.<anonymous closure> (package:flutter/src/foundation/diagnostics.dart:2992:17)
#4 DiagnosticableNode.builder (package:flutter/src/foundation/diagnostics.dart:2995:8)
#5 DiagnosticableNode.getProperties (package:flutter/src/foundation/diagnostics.dart:3009:105)
#6 TextTreeRenderer._debugRender (package:flutter/src/foundation/diagnostics.dart:1244:63)
#7 TextTreeRenderer.render (package:flutter/src/foundation/diagnostics.dart:1121:14)
#8 DiagnosticsNode.toStringDeep.<anonymous closure> (package:flutter/src/foundation/diagnostics.dart:1776:9)
#9 DiagnosticsNode.toStringDeep (package:flutter/src/foundation/diagnostics.dart:1783:6)
#10 DiagnosticsNode.toString.<anonymous closure> (package:flutter/src/foundation/diagnostics.dart:1694:18)
#11 DiagnosticsNode.toString (package:flutter/src/foundation/diagnostics.dart:1706:6)
#12 Diagnosticable.toString.<anonymous closure> (package:flutter/src/foundation/diagnostics.dart:3168:78)
#13 Diagnosticable.toString (package:flutter/src/foundation/diagnostics.dart:3170:6)
#14 _StringBase._interpolate (dart:core-patch/string_patch.dart:853:19)
#15 RepositoryProvider.of (package:flutter_bloc/src/repository_provider.dart:78:12)
#16 MyApp.build.<anonymous closure> (package:api_call_sample/main.dart:20:36)
#17 _CreateInheritedProviderState.value (package:provider/src/inherited_provider.dart:736:36)
#18 _InheritedProviderScopeElement.value (package:provider/src/inherited_provider.dart:590:33)
#19 Provider.of (package:provider/src/provider.dart:303:37)
#20 ReadContext.read (package:provider/src/provider.dart:649:21)
#21 _BlocBuilderBaseState.initState (package:flutter_bloc/src/bloc_builder.dart:130:36)
#22 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:4942:57)
#23 ComponentElement.mount (package:flutter/src/widgets/framework.dart:4781:5)
#24 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3817:16)
#25 MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6350:36)
#26 MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6362:32)
... Normal element mounting (19 frames)
#45 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3817:16)
#46 MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6350:36)
#47 MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6362:32)
... Normal element mounting (99 frames)
#146 _InheritedProviderScopeElement.mount (package:provider/src/inherited_provider.dart:411:11)
... Normal element mounting (7 frames)
#153 SingleChildWidgetElementMixin.mount (package:nested/nested.dart:222:11)
... Normal element mounting (7 frames)
#160 SingleChildWidgetElementMixin.mount (package:nested/nested.dart:222:11)
... Normal element mounting (275 frames)
#435 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3817:16)
#436 MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6350:36)
#437 MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6362:32)
... Normal element mounting (377 frames)
#814 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3817:16)
#815 Element.updateChild (package:flutter/src/widgets/framework.dart:3551:18)
#816 RenderObjectToWidgetElement._rebuild (package:flutter/src/widgets/binding.dart:1202:16)
#817 RenderObjectToWidgetElement.mount (package:flutter/src/widgets/binding.dart:1171:5)
#818 RenderObjectToWidgetAdapter.attachToRenderTree.<anonymous closure> (package:flutter/src/widgets/binding.dart:1119:18)
#819 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2597:19)
#820 RenderObjectToWidgetAdapter.attachToRenderTree (package:flutter/src/widgets/binding.dart:1118:13)
#821 WidgetsBinding.attachRootWidget (package:flutter/src/widgets/binding.dart:953:7)
#822 WidgetsBinding.scheduleAttachRootWidget.<anonymous closure> (package:flutter/src/widgets/binding.dart:933:7)
(elided 11 frames from class _RawReceivePortImpl, class _Timer, dart:async, and dart:async-patch)
Another exception was thrown: Each child must be laid out exactly once.
The way you create the JokeBloc in the BlocProvider doesn't work within this lifecycle,
replacing this code with the code below should fix the problem
create: (_) => JokeBloc(JokeRepository())

Flutter-Test: Getting BlocProvider.of() called with a context that does not container Bloc

I am trying to test my submit button which fires a bloc event onPress.
SubmitButton.dart - Widget
class AuthenticationSubmitButton extends StatefulWidget {
final String buttonLabel;
final TextEditingController _userEmailController;
final TextEditingController _passwordController;
AuthenticationSubmitButton(
this.buttonLabel, this._userEmailController, this._passwordController);
#override
_AuthenticationSubmitButtonState createState() =>
_AuthenticationSubmitButtonState();
}
class _AuthenticationSubmitButtonState
extends State<AuthenticationSubmitButton> {
#override
Widget build(BuildContext context) {
Size screenSize = MediaQuery.of(context).size;
final _authBloc = BlocProvider.of<AuthenticationBloc>(context);
return Container(
child: FlatButton.icon(
height: screenSize.height * 0.07,
minWidth: screenSize.width * 0.5,
padding: EdgeInsets.all(10),
color: Colors.green,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
onPressed: () {
final email = widget._userEmailController.text.trim();
final password = widget._passwordController.text.trim();
_authBloc.add(UserLoginEvent(email, password));
},
icon: Icon(Icons.keyboard_return_rounded),
label: Text(
widget.buttonLabel,
style: SubmitButtonStyle,
),
),
);
}
}
As you can see I am calling the event UserLoginEvent
authentication_events.dart
#immutable
abstract class AuthenticationEvent {}
/**
* Login Event
* Logout Event
*/
class UserLoginEvent extends AuthenticationEvent {
final String userEmail;
final String userPassword;
UserLoginEvent(this.userEmail, this.userPassword);
}
class ClearLoginEvent extends AuthenticationEvent {
}
And here is my authentication states
authentication_states.dart
#immutable
abstract class AuthenticationState extends Equatable {
}
class AuthenticationInitial extends AuthenticationState {
#override
List<Object> get props => [];
}
/**
* LoginSuccessful
* LoginFailed
* LogoutSuccessful
*/
class LoginSuccessful extends AuthenticationState {
#override
List<Object> get props => [];
}
class LoginError extends AuthenticationState {
#override
List<Object> get props => [];
}
authentication_bloc.dart
class AuthenticationBloc
extends Bloc<AuthenticationEvent, AuthenticationState> {
AuthenticationBloc({this.userRepository}) : super(AuthenticationInitial());
UserRepository userRepository;
#override
Stream<AuthenticationState> mapEventToState(
AuthenticationEvent event,
) async* {
if (event is UserLoginEvent) {
UserRepository repository = userRepository ?? UserRepository();
try {
bool loggedIn = await repository.authenticateUserWithCredentials(
event.userEmail, event.userPassword);
if (loggedIn) {
yield LoginSuccessful();
} else {
yield LoginError();
}
} catch (e) {
yield EmptyLoginCredentials();
}
} else if (event is ClearLoginEvent) {
yield AuthenticationInitial();
}
}
}
And finally my test for submit button
> submit_button_test.dart
class MockAuthBloc extends MockBloc<AuthenticationState>
implements AuthenticationBloc {}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
MockAuthBloc authBloc = MockAuthBloc();
TextEditingController _userEmailController;
TextEditingController _passwordController;
setUp(() {
_userEmailController = TextEditingController();
_passwordController = TextEditingController();
authBloc = MockAuthBloc();
});
tearDown(() {
_userEmailController.dispose();
_passwordController.dispose();
authBloc?.close();
});
///Provide Material App for giving access to MediaQuery
///Wrap any widget that needs Material widget
Widget buildTestableWidget(Widget widget) {
return MediaQuery(
data: MediaQueryData(),
child: BlocProvider.value(
value: authBloc,
child: MaterialApp(
home: Material(
child: widget,
),
),
),
);
}
group('Testing Submit button |', () {
testWidgets('description', (WidgetTester tester) async {
whenListen(
authBloc,
Stream.fromIterable(<AuthenticationState>[LoginSuccessful()]),
);
await tester.pumpWidget(buildTestableWidget(AuthenticationSubmitButton(
'Submit', _userEmailController, _passwordController)));
final buttonFinder = find.byType(FlatButton);
final button = tester.firstWidget(buttonFinder);
});
});
}
Could you please tell me what am I doing wrong here?
Below is my error
00:03 +19: /home/bhuvanesh/code/kaadhal_host_client/test/screens/Authentication/widgets/submit_button_test.dart: Testing Submit button | description
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following assertion was thrown building AuthenticationSubmitButton(dirty, dependencies:
[MediaQuery], state: _AuthenticationSubmitButtonState#da4f9):
BlocProvider.of() called with a context that does not contain a Bloc/Cubit of type
AuthenticationBloc.
No ancestor could be found starting from the context that was passed to
BlocProvider.of<AuthenticationBloc>().
This can happen if the context you used comes from a widget above the BlocProvider.
The context used was: AuthenticationSubmitButton(dirty, dependencies: [MediaQuery], state:
_AuthenticationSubmitButtonState#da4f9)
The relevant error-causing widget was:
AuthenticationSubmitButton
file:///home/bhuvanesh/code/kaadhal_host_client/test/screens/Authentication/widgets/submit_button_test.dart:57:51
When the exception was thrown, this was the stack:
#0 BlocProvider.of (package:flutter_bloc/src/bloc_provider.dart:121:7)
#1 _AuthenticationSubmitButtonState.build (package:kaadhal_host_client/screens/Authentication/widgets/submit_button.dart:26:36)
#2 StatefulElement.build (package:flutter/src/widgets/framework.dart:4744:28)
#3 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4627:15)
#4 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4800:11)
#5 Element.rebuild (package:flutter/src/widgets/framework.dart:4343:5)
#6 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4606:5)
#7 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:4791:11)
#8 ComponentElement.mount (package:flutter/src/widgets/framework.dart:4601:5)
... Normal element mounting (174 frames)
#182 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
#183 MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6236:32)
... Normal element mounting (267 frames)
#450 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
#451 Element.updateChild (package:flutter/src/widgets/framework.dart:3327:18)
#452 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4652:16)
#453 _InheritedProviderScopeElement.performRebuild (package:provider/src/inherited_provider.dart:426:11)
#454 Element.rebuild (package:flutter/src/widgets/framework.dart:4343:5)
#455 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4606:5)
#456 ComponentElement.mount (package:flutter/src/widgets/framework.dart:4601:5)
... Normal element mounting (7 frames)
#463 SingleChildWidgetElementMixin.mount (package:nested/nested.dart:223:11)
... Normal element mounting (7 frames)
#470 SingleChildWidgetElementMixin.mount (package:nested/nested.dart:223:11)
... Normal element mounting (7 frames)
#477 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
#478 Element.updateChild (package:flutter/src/widgets/framework.dart:3324:20)
#479 RenderObjectToWidgetElement._rebuild (package:flutter/src/widgets/binding.dart:1252:16)
#480 RenderObjectToWidgetElement.update (package:flutter/src/widgets/binding.dart:1230:5)
#481 RenderObjectToWidgetElement.performRebuild (package:flutter/src/widgets/binding.dart:1244:7)
#482 Element.rebuild (package:flutter/src/widgets/framework.dart:4343:5)
#483 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2730:33)
#484 AutomatedTestWidgetsFlutterBinding.drawFrame (package:flutter_test/src/binding.dart:1088:18)
#485 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:302:5)
#486 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1117:15)
#487 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1055:9)
#488 AutomatedTestWidgetsFlutterBinding.pump.<anonymous closure> (package:flutter_test/src/binding.dart:961:9)
#491 TestAsyncUtils.guard (package:flutter_test/src/test_async_utils.dart:72:41)
#492 AutomatedTestWidgetsFlutterBinding.pump (package:flutter_test/src/binding.dart:948:27)
#493 WidgetTester.pumpWidget.<anonymous closure> (package:flutter_test/src/widget_tester.dart:524:22)
#496 TestAsyncUtils.guard (package:flutter_test/src/test_async_utils.dart:72:41)
#497 WidgetTester.pumpWidget (package:flutter_test/src/widget_tester.dart:521:27)
#498 main.<anonymous closure>.<anonymous closure> (file:///home/bhuvanesh/code/kaadhal_host_client/test/screens/Authentication/widgets/submit_button_test.dart:57:20)
#499 main.<anonymous closure>.<anonymous closure> (file:///home/bhuvanesh/code/kaadhal_host_client/test/screens/Authentication/widgets/submit_button_test.dart:46:32)
#500 testWidgets.<anonymous closure>.<anonymous closure> (package:flutter_test/src/widget_tester.dart:146:29)
#511 FakeAsync.flushMicrotasks (package:fake_async/fake_async.dart:193:32)
#512 AutomatedTestWidgetsFlutterBinding.runTest.<anonymous closure> (package:flutter_test/src/binding.dart:1189:17)
#513 AutomatedTestWidgetsFlutterBinding.runTest.<anonymous closure> (package:flutter_test/src/binding.dart:1177:35)
(elided 29 frames from dart:async and package:stack_trace)
════════════════════════════════════════════════════════════════════════════════════════════════════
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following StateError was thrown running a test:
Bad state: No element
When the exception was thrown, this was the stack:
#0 Iterable.first (dart:core/iterable.dart:524:7)
#1 WidgetController.firstWidget (package:flutter_test/src/controller.dart:79:30)
#2 main.<anonymous closure>.<anonymous closure> (file:///home/bhuvanesh/code/kaadhal_host_client/test/screens/Authentication/widgets/submit_button_test.dart:60:29)
<asynchronous suspension>
#3 main.<anonymous closure>.<anonymous closure> (file:///home/bhuvanesh/code/kaadhal_host_client/test/screens/Authentication/widgets/submit_button_test.dart)
#4 testWidgets.<anonymous closure>.<anonymous closure> (package:flutter_test/src/widget_tester.dart:146:29)
<asynchronous suspension>
#5 testWidgets.<anonymous closure>.<anonymous closure> (package:flutter_test/src/widget_tester.dart)
#6 TestWidgetsFlutterBinding._runTestBody (package:flutter_test/src/binding.dart:784:19)
<asynchronous suspension>
#9 TestWidgetsFlutterBinding._runTest (package:flutter_test/src/binding.dart:764:14)
#10 AutomatedTestWidgetsFlutterBinding.runTest.<anonymous closure> (package:flutter_test/src/binding.dart:1173:24)
#11 FakeAsync.run.<anonymous closure>.<anonymous closure> (package:fake_async/fake_async.dart:178:54)
#16 withClock (package:clock/src/default.dart:48:10)
#17 FakeAsync.run.<anonymous closure> (package:fake_async/fake_async.dart:178:22)
#22 FakeAsync.run (package:fake_async/fake_async.dart:178:7)
#23 AutomatedTestWidgetsFlutterBinding.runTest (package:flutter_test/src/binding.dart:1170:15)
#24 testWidgets.<anonymous closure> (package:flutter_test/src/widget_tester.dart:138:24)
#25 Declarer.test.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart:175:19)
<asynchronous suspension>
#26 Declarer.test.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart)
#31 Declarer.test.<anonymous closure> (package:test_api/src/backend/declarer.dart:173:13)
#32 Invoker.waitForOutstandingCallbacks.<anonymous closure> (package:test_api/src/backend/invoker.dart:231:15)
#37 Invoker.waitForOutstandingCallbacks (package:test_api/src/backend/invoker.dart:228:5)
#38 Invoker._onRun.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/invoker.dart:383:17)
<asynchronous suspension>
#39 Invoker._onRun.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/invoker.dart)
#44 Invoker._onRun.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/invoker.dart:370:9)
#45 Invoker._guardIfGuarded (package:test_api/src/backend/invoker.dart:415:15)
#46 Invoker._onRun.<anonymous closure> (package:test_api/src/backend/invoker.dart:369:7)
#53 Invoker._onRun (package:test_api/src/backend/invoker.dart:368:11)
#54 LiveTestController.run (package:test_api/src/backend/live_test_controller.dart:153:11)
#55 RemoteListener._runLiveTest.<anonymous closure> (package:test_api/src/remote_listener.dart:256:16)
#60 RemoteListener._runLiveTest (package:test_api/src/remote_listener.dart:255:5)
#61 RemoteListener._serializeTest.<anonymous closure> (package:test_api/src/remote_listener.dart:208:7)
#79 _GuaranteeSink.add (package:stream_channel/src/guarantee_channel.dart:125:12)
#80 new _MultiChannel.<anonymous closure> (package:stream_channel/src/multi_channel.dart:159:31)
#84 CastStreamSubscription._onData (dart:_internal/async_cast.dart:85:11)
#118 new _WebSocketImpl._fromSocket.<anonymous closure> (dart:_http/websocket_impl.dart:1145:21)
#126 _WebSocketProtocolTransformer._messageFrameEnd (dart:_http/websocket_impl.dart:338:23)
#127 _WebSocketProtocolTransformer.add (dart:_http/websocket_impl.dart:232:46)
#137 _Socket._onData (dart:io-patch/socket_patch.dart:2044:41)
#146 new _RawSocket.<anonymous closure> (dart:io-patch/socket_patch.dart:1580:33)
#147 _NativeSocket.issueReadEvent.issue (dart:io-patch/socket_patch.dart:1076:14)
(elided 111 frames from dart:async and package:stack_trace)
The test description was:
description
════════════════════════════════════════════════════════════════════════════════════════════════════
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following message was thrown:
Multiple exceptions (2) were detected during the running of the current test, and at least one was
unexpected.
════════════════════════════════════════════════════════════════════════════════════════════════════
00:03 +19 -1: /home/bhuvanesh/code/kaadhal_host_client/test/screens/Authentication/widgets/submit_button_test.dart: Testing Submit button | description [E]
Test failed. See exception logs above.
The test description was: description
Reasons-
You are coming on this class thought navigator
Your parent is not using same bloc
Solution-
You can use bloc here by passing it to constructor

context doesn't match when testing Provider

I have written a test to check that a provider works as expected, however i get the following exception when checking that the context matches the providers context:
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following TestFailure object was thrown running a test:
Expected:
_InheritedProvderElement<AuthScreen>:<ChangeNotifierProvider<AuthScreen>-[GlobalKey#11403](value:
Instance of 'AuthScreen', listening to value)>
Actual:
_DefaultInheritedProviderScopeElement<AuthScreen>:<_DefaultInheritedProviderScope<AuthScreen>(value:
Instance of 'AuthScreen', listening to value)>
When the exception was thrown, this was the stack:
#4 main.<anonymous closure> (file:///home/hannes/Documents/StudioProjects/brf/test/Authentication/authenticate_test.dart:24:5)
<asynchronous suspension>
#5 testWidgets.<anonymous closure>.<anonymous closure> (package:flutter_test/src/widget_tester.dart:140:29)
<asynchronous suspension>
#6 TestWidgetsFlutterBinding._runTestBody (package:flutter_test/src/binding.dart:699:19)
<asynchronous suspension>
#9 TestWidgetsFlutterBinding._runTest (package:flutter_test/src/binding.dart:679:14)
#10 AutomatedTestWidgetsFlutterBinding.runTest.<anonymous closure> (package:flutter_test/src/binding.dart:1079:24)
#16 AutomatedTestWidgetsFlutterBinding.runTest (package:flutter_test/src/binding.dart:1076:15)
#17 testWidgets.<anonymous closure> (package:flutter_test/src/widget_tester.dart:133:24)
#18 Declarer.test.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart:171:27)
<asynchronous suspension>
#19 Invoker.waitForOutstandingCallbacks.<anonymous closure> (package:test_api/src/backend/invoker.dart:242:15)
#24 Invoker.waitForOutstandingCallbacks (package:test_api/src/backend/invoker.dart:239:5)
#25 Declarer.test.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart:169:33)
#30 Declarer.test.<anonymous closure> (package:test_api/src/backend/declarer.dart:168:13)
#31 Invoker._onRun.<anonymous closure>.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/invoker.dart:392:25)
#45 _Timer._runTimers (dart:isolate-patch/timer_impl.dart:398:19)
#46 _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:429:5)
#47 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:168:12)
(elided 28 frames from class _FakeAsync, package dart:async, package dart:async-patch, and package stack_trace)
This was caught by the test expectation on the following line:
file:///home/hannes/Documents/StudioProjects/brf/test/Authentication/authenticate_test.dart line 24
The test description was:
AuthScreen provider changes value
════════════════════════════════════════════════════════════════════════════════════════════════════
Also, _childKey.currentContext is null. I don't know if that is related or if it's something else that I'm doing wrong.
I have tried to follow this guide, and my test looks like this:
import 'package:brf/models/auth_screen.dart';
import 'package:brf/screens/authenticate/authenticate.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
setUp(() {
AuthScreen();
});
testWidgets('AuthScreen provider changes value', (WidgetTester tester) async {
final _providerKey = GlobalKey();
final _childKey = GlobalKey();
BuildContext context;
await tester.pumpWidget(
MaterialApp(
home: ChangeNotifierProvider<AuthScreen>(
key: _providerKey,
create: (c) {
context = c;
return AuthScreen();
},
child: Authenticate(key: _childKey),
),
),
);
expect(context, equals(_providerKey.currentContext));
expect(Provider.of<AuthScreen>(_childKey.currentContext).showSignIn, true);
Provider.of<AuthScreen>(context, listen: false).switchScreen();
await Future.microtask(tester.pump);
expect(Provider.of<AuthScreen>(_childKey.currentContext).showSignIn, false);
});
}
And finally AuthScreen looks like this:
import 'package:flutter/material.dart';
class AuthScreen extends ChangeNotifier{
bool _showSignIn = true;
bool get showSignIn => _showSignIn;
void switchScreen(){
_showSignIn = !_showSignIn;
notifyListeners();
}
}
This is the error for the null context you passed
you this one:
Builder(builder: (context) => Widget here
Try like this where you want to pass the context:
MaterialApp(
home: Builder(builder: (context) => ChangeNotifierProvider<AuthScreen>(
key: _providerKey,
create: (c) {
context = c;
return AuthScreen();
},
child: Authenticate(key: _childKey),
),
),
);

Flutter: Make sure to call FirebaseApp.initializeApp(Context) first

I am writing a FLUTTER application and I am trying to upload an image on the Firebase storage. This is a simple test app I've created to reproduce the error.
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'package:path_provider/path_provider.dart';
import 'package:firebase_storage/firebase_storage.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
File image;
Future<File> getImageFileFromAssets(String path) async {
final byteData = await rootBundle.load('assets/$path');
final file = File('${(await getTemporaryDirectory()).path}/$path');
await file.writeAsBytes(byteData.buffer
.asUint8List(byteData.offsetInBytes, byteData.lengthInBytes));
return file;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Test App'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
height: 300,
width: 450,
child: image == null ? null : Image.file(image),
),
RaisedButton(
child: Text('Submit'),
onPressed: () async {
final fileName = 'imageName';
final firebaseStorageRef =
FirebaseStorage.instance.ref().child('userFolder');
final uploadTask =
firebaseStorageRef.child(fileName).putFile(image);
await uploadTask.onComplete;
},
),
RaisedButton(
child: Text('Load immagine'),
onPressed: () async {
image = await getImageFileFromAssets('test.jpg');
setState(() {});
},
),
],
),
),
);
}
}
As you can see when I click on the Load Image button I take an image from the assets and I store it in a File object, and it works fine. Then when I want to upload that image on Firebase's storage using the Submit button I get this error:
E/MethodChannel#plugins.flutter.io/firebase_storage(19436): Failed to handle method call
E/MethodChannel#plugins.flutter.io/firebase_storage(19436): java.lang.IllegalStateException: Default FirebaseApp is not initialized in this process com.example.test_project. Make sure to call FirebaseApp.initializeApp(Context) first.
E/MethodChannel#plugins.flutter.io/firebase_storage(19436): at com.google.firebase.FirebaseApp.getInstance(com.google.firebase:firebase-common##17.0.0:234)
E/MethodChannel#plugins.flutter.io/firebase_storage(19436): at com.google.firebase.storage.FirebaseStorage.getInstance(com.google.firebase:firebase-storage##17.0.0:86)
E/MethodChannel#plugins.flutter.io/firebase_storage(19436): at io.flutter.plugins.firebase.storage.FirebaseStoragePlugin.onMethodCall(FirebaseStoragePlugin.java:57)
E/MethodChannel#plugins.flutter.io/firebase_storage(19436): at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:222)
E/MethodChannel#plugins.flutter.io/firebase_storage(19436): at io.flutter.embedding.engine.dart.DartMessenger.handleMessageFromDart(DartMessenger.java:96)
E/MethodChannel#plugins.flutter.io/firebase_storage(19436): at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(FlutterJNI.java:656)
E/MethodChannel#plugins.flutter.io/firebase_storage(19436): at android.os.MessageQueue.nativePollOnce(Native Method)
E/MethodChannel#plugins.flutter.io/firebase_storage(19436): at android.os.MessageQueue.next(MessageQueue.java:326)
E/MethodChannel#plugins.flutter.io/firebase_storage(19436): at android.os.Looper.loop(Looper.java:160)
E/MethodChannel#plugins.flutter.io/firebase_storage(19436): at android.app.ActivityThread.main(ActivityThread.java:6669)
E/MethodChannel#plugins.flutter.io/firebase_storage(19436): at java.lang.reflect.Method.invoke(Native Method)
E/MethodChannel#plugins.flutter.io/firebase_storage(19436): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
E/MethodChannel#plugins.flutter.io/firebase_storage(19436): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
E/flutter (19436): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: PlatformException(error, Default FirebaseApp is not initialized in this process com.example.test_project. Make sure to call FirebaseApp.initializeApp(Context) first., null)
E/flutter (19436): #0 StandardMethodCodec.decodeEnvelope
package:flutter/…/services/message_codecs.dart:569
E/flutter (19436): #1 MethodChannel.invokeMethod
package:flutter/…/services/platform_channel.dart:316
E/flutter (19436): <asynchronous suspension>
E/flutter (19436): #2 _StorageFileUploadTask._platformStart
package:firebase_storage/src/upload_task.dart:130
E/flutter (19436): #3 StorageUploadTask._start
package:firebase_storage/src/upload_task.dart:35
E/flutter (19436): <asynchronous suspension>
E/flutter (19436): #4 StorageReference.putFile
package:firebase_storage/src/storage_reference.dart:65
E/flutter (19436): #5 _MyHomePageState.build.<anonymous closure>
package:test_project/main.dart:60
E/flutter (19436): <asynchronous suspension>
E/flutter (19436): #6 _InkResponseState._handleTap
package:flutter/…/material/ink_well.dart:654
E/flutter (19436): #7 _InkResponseState.build.<anonymous closure>
package:flutter/…/material/ink_well.dart:729
E/flutter (19436): #8 GestureRecognizer.invokeCallback
package:flutter/…/gestures/recognizer.dart:182
E/flutter (19436): #9 TapGestureRecognizer._checkUp
package:flutter/…/gestures/tap.dart:365
E/flutter (19436): #10 TapGestureRecognizer.handlePrimaryPointer
package:flutter/…/gestures/tap.dart:275
E/flutter (19436): #11 PrimaryPointerGestureRecognizer.handleEvent
package:flutter/…/gestures/recognizer.dart:455
E/flutter (19436): #12 PointerRouter._dispatch
package:flutter/…/gestures/pointer_router.dart:75
E/flutter (19436): #13 PointerRouter.route
package:flutter/…/gestures/pointer_router.dart:102
E/flutter (19436): #14 GestureBinding.handleEvent
package:flutter/…/gestures/binding.dart:218
E/flutter (19436): #15 GestureBinding.dispatchEvent
package:flutter/…/gestures/binding.dart:198
E/flutter (19436): #16 GestureBinding._handlePointerEvent
package:flutter/…/gestures/binding.dart:156
E/flutter (19436): #17 GestureBinding._flushPointerEventQueue
package:flutter/…/gestures/binding.dart:102
E/flutter (19436): #18 GestureBinding._handlePointerDataPacket
package:flutter/…/gestures/binding.dart:86
E/flutter (19436): #19 _rootRunUnary (dart:async/zone.dart:1136:13)
E/flutter (19436): #20 _CustomZone.runUnary (dart:async/zone.dart:1029:19)
E/flutter (19436): #21 _CustomZone.runUnaryGuarded (dart:async/zone.dart:931:7)
E/flutter (19436): #22 _invoke1 (dart:ui/hooks.dart:263:10)
E/flutter (19436): #23 _dispatchPointerDataPacket (dart:ui/hooks.dart:172:5)
E/flutter (19436):
Database's rules are the public ones:
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write;
}
}
}
Can someone tell me what am I doing wrong?
According to docs just change your main method:
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
For who come here, I solved the problem. There is a lot of stuff to do, such as add your app to your Firebase project and edit some files.
The only thing to do is to read better the docs and follow all the steps:
Add Firebase to your Flutter app
All Firebase versions have been updated and now you have to call Firebase.initializeApp() before using any Firebase product, for example:
First, all Firebase products now depend on firebase_core version (0.5.0+), therefore you need to add it in the pubspec.yaml file:
dependencies:
flutter:
sdk: flutter
firebase_core : ^0.5.0
Then you have to call Firebase.initializeApp():
In the main.dart:
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(); //Make sure you imported firebase_core
runApp(MaterialApp(
home: GettingStartedPage(),
));
}
import 'package:firebase_core/firebase_core.dart';
Add the apply plugin to the [project]/android/app/build.gradle file.
apply plugin: 'com.google.gms.google-services'
Add this at root gradle in android/build.gradle
classpath 'com.google.gms:google-services:4.3.5'
check https://github.com/flutter/plugins/blob/master/packages/firebase_auth/README.md

From StatefulWidget navigate to StatelessWidget runs the last builder but also the first builder

Is there a way to prevent the build() from being called multiple times?
The next code creates two pages, each with one button, the button on FirstPage navigates to SecondPage, and the one on SecondsPage goes back to FirstPage.
The problem is that if you click the button on FirstPage it runs the SecondPage build() but it also runs the FirstPage build().
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'First page',
home: FirstPage(),
);
}
}
class FirstPage extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _FirstPageState();
}
}
class _FirstPageState extends State<FirstPage> {
#override
Widget build(BuildContext context) {
print('---------- In FirstPage build ----------');
return Scaffold(
appBar: AppBar(
title: Text('First page'),
),
body: Column(
children: [
Text('First page body'),
FlatButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondPage()),
);
},
child: Text('Go to second page')
)
]
)
);
}
}
class SecondPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
print('---------- In SecondPage build ----------');
return Scaffold(
appBar: AppBar(
title: Text('Second page'),
),
body: Column(
children: [
Text('Second page body'),
FlatButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Go back')
)
]
)
);
}
}
Console output:
Performing hot restart...
D/dalvikvm(23908): threadid=12: interp stack at 0x76040000
Restarted app in 3,849ms.
I/flutter (23908): ---------- In FirstPage build ----------
I/SurfaceTextureClient(23908): [STC::queueBuffer] (this:0x76b39810) fps:0.07, dur:14731.13, max:14731.13, min:14731.13
I/SurfaceTextureClient(23908): [STC::queueBuffer] this:0x76b39810, api:1, last queue time elapsed:14731.13
After click button:
V/Provider/Settings(23908): from db cache, name = sound_effects_enabled , value = 0
I/flutter (23908): ---------- In SecondPage build ----------
I/SurfaceTextureClient(23908): [STC::queueBuffer] (this:0x76b39810) fps:0.24, dur:4140.60, max:4140.60, min:4140.60
I/flutter (23908): ---------- In FirstPage build ----------
Thanks for your help.
EDIT:
I tryed using popAndPushNamed() on FirstPage it just runs the build on the SecondPage but if I try to go back with:
Navigator.popAndPushNamed(
context,
'/'
);
I get the error:
I/flutter ( 5005): ══╡ EXCEPTION CAUGHT BY GESTURE ╞═══════════════════════════════════════════════════════════════════
I/flutter ( 5005): The following assertion was thrown while handling a gesture:
I/flutter ( 5005): Cannot reuse a MaterialPageRoute<dynamic> after disposing it.
I/flutter ( 5005): 'package:flutter/src/widgets/routes.dart': Failed assertion: line 215 pos 12:
I/flutter ( 5005): '!_transitionCompleter.isCompleted'
I/flutter ( 5005): Either the assertion indicates an error in the framework itself, or we should provide substantially
I/flutter ( 5005): more information in this error message to help you determine and fix the underlying cause.
I/flutter ( 5005): In either case, please report this assertion by filing a bug on GitHub:
I/flutter ( 5005): https://github.com/flutter/flutter/issues/new
I/flutter ( 5005): When the exception was thrown, this was the stack:
I/flutter ( 5005): #2 TransitionRoute.didPopNext (package:flutter/src/widgets/routes.dart)
I/flutter ( 5005): #3 NavigatorState.pop (package:flutter/src/widgets/navigator.dart:1691:23)
I/flutter ( 5005): #4 NavigatorState.popAndPushNamed (package:flutter/src/widgets/navigator.dart:1399:5)
I/flutter ( 5005): #5 Navigator.popAndPushNamed (package:flutter/src/widgets/navigator.dart:731:34)
I/flutter ( 5005): #6 SecondPage.build.<anonymous closure> (file:///home/ncs/Documents/flutter/src/test1/lib/main.dart:83:25)
I/flutter ( 5005): #7 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:494:14)
I/flutter ( 5005): #8 _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:549:30)
I/flutter ( 5005): #9 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:102:24)
I/flutter ( 5005): #10 TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:161:9)
I/flutter ( 5005): #11 TapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:94:7)
I/flutter ( 5005): #12 PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:315:9)
I/flutter ( 5005): #13 PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:73:12)
I/flutter ( 5005): #14 PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:101:11)
I/flutter ( 5005): #15 _WidgetsFlutterBinding&BindingBase&GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:143:19)
I/flutter ( 5005): #16 _WidgetsFlutterBinding&BindingBase&GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:121:22)
I/flutter ( 5005): #17 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:101:7)
I/flutter ( 5005): #18 _WidgetsFlutterBinding&BindingBase&GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:64:7)
I/flutter ( 5005): #19 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:48:7)
I/flutter ( 5005): #20 _invoke1 (dart:ui/hooks.dart:134:13)
I/flutter ( 5005): #21 _dispatchPointerDataPacket (dart:ui/hooks.dart:91:5)
I/flutter ( 5005): (elided 2 frames from class _AssertionError)
I/flutter ( 5005): Handler: onTap
I/flutter ( 5005): Recognizer:
I/flutter ( 5005): TapGestureRecognizer#94626(debugOwner: GestureDetector, state: possible, won arena, finalPosition:
I/flutter ( 5005): Offset(65.3, 119.6), sent tap down)
I/flutter ( 5005): ════════════════════════════════════════════════════════════════════════════════════════════════════
The only way I'm able to remove the unwanted build is by having a condition like::
class _FirstPageState extends State<FirstPage> {
bool _canBuild = true;
#override
Widget build(BuildContext context) {
if (!_canBuild) {
return Container();
}
print('---------- In FirstPage build ----------');
...
onPressed: () {
_canBuild = false;
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondPage()),
).then((_) {
_canBuild = true;
});
},
...
Is this a bad practice or can create any problems?
it is just because of widget is still in to the stack of routes. i think that flutter re-render widgets which are in the stack. if you pop FirstPage before routing to SecondPage the it will not display the message of first widget.
EDIT:
how you can use.
onPressed: () {
Navigator.pop(context);
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondPage()),
);
},
Flutter always builds every "page" (widget) in the navigation stack after every push/pop. This is normal and intended behavior, so that every widget can update itself if needed.
Widget's build methods are supposed to be idempotent, whilst usually it only builds when you think it will, the framework might decide at any point to build a widget for any reason - you can't rely on any widget not building.
This is not actually a problem normally, Flutter compares all new widgets with all old widgets on a build, if the widgets are identical they will not be replaced or in any other way affected.
The short answer is thus "No", of course if you want to you can hack around this (e.g. by overriding the navigator), you definitely can.
You can view the code related to building the children of a widget (including navigator) here: https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/widgets/framework.dart
But ideally you just want to assume anything can build at any time -- as it can. Flutter makes no promises as to when it will (or wont) build your widgets, any code that is not written to take this into account is liable to break!
See this issue: https://github.com/flutter/flutter/issues/11655