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

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

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 MultiProvider: setState() or markNeedsBuild() called during build

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});

I am getting error like this Unhandled Exception: Looking up a deactivated widget's ancestor is unsafe

What I trying to do here is getting data from the 000webhost.com and passing that to my model class. That model class is being passed to the provider. Now when I try to display the information in my screen i am getting error.
In this case i have a model class called StudentData.
class StudentData {
final String rollNumber;
final String firstName;
final String lastName;
StudentData({
this.rollNumber,
this.firstName,
this.lastName,
});
}
Here I am fetching data using http package from internet.
And passing the decoded data to the StudentData class and passing that to my data_provider
import 'package:http/http.dart' as http;
void getStudentData(String currentEmail, BuildContext context) async {
final _url = 'https://aaa.000webhostapp.com/getStudentData.php';
final response = await http.post(_url, body: {'email': currentEmail});
var data = response.body;
final decodedData = jsonDecode(data);
final myRollNumber = decodedData['roll_number'];
final myFirstName = decodedData['first_name'];
final myLastName = decodedData['last_name'];
final myStudentData = StudentData(
rollNumber: myRollNumber, firstName: myFirstName, lastName: myLastName);
Provider.of<DataProvider>(context, listen: false)
.getMyStudentData(myStudentData);
}
Here is my DataProvider
class DataProvider extends ChangeNotifier {
StudentData myStudentData;
void getMyStudentData(StudentData studentData) {
myStudentData = studentData;
notifyListeners();
}
}
After that I have tried to fetch those information in my Screen
class StudentDashboard extends StatelessWidget {
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Center(
child:
Text(Provider.of<DataProvider>(context).myStudentData.rollNumber),
),
),
);
}
}
Then the error be like
======== Exception caught by widgets library =======================================================
The following NoSuchMethodError was thrown building StudentDashboard(dirty, dependencies: [_InheritedProviderScope<DataProvider>]):
The getter 'rollNumber' was called on null.
Receiver: null
Tried calling: rollNumber
The relevant error-causing widget was:
StudentDashboard file:///D:/Other/App/Flutter/my_ecampus/lib/views/screens/auth_screens/login_screen.dart:62:53
When the exception was thrown, this was the stack:
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)
#1 StudentDashboard.build (package:my_ecampus/views/screens/main_screens/student_screens/student_dashboard.dart:38:69)
#2 StatelessElement.build (package:flutter/src/widgets/framework.dart:4701:28)
#3 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4627:15)
#4 Element.rebuild (package:flutter/src/widgets/framework.dart:4343:5)
...
====================================================================================================
E/flutter ( 7682): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: Looking up a deactivated widget's ancestor is unsafe.
E/flutter ( 7682): At this point the state of the widget's element tree is no longer stable.
E/flutter ( 7682): To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling dependOnInheritedWidgetOfExactType() in the widget's didChangeDependencies() method.
E/flutter ( 7682): #0 Element._debugCheckStateIsActiveForAncestorLookup.<anonymous closure> (package:flutter/src/widgets/framework.dart:3906:9)
E/flutter ( 7682): #1 Element._debugCheckStateIsActiveForAncestorLookup (package:flutter/src/widgets/framework.dart:3920:6)
E/flutter ( 7682): #2 Element.getElementForInheritedWidgetOfExactType (package:flutter/src/widgets/framework.dart:3986:12)
E/flutter ( 7682): #3 Provider._inheritedElementOf (package:provider/src/provider.dart:324:34)
E/flutter ( 7682): #4 Provider.of (package:provider/src/provider.dart:281:30)
E/flutter ( 7682): #5 getStudentData (package:my_ecampus/business_view/services/database/getData_database.dart:19:12)
E/flutter ( 7682): <asynchronous suspension>
E/flutter ( 7682): #6 LoginScreen._login (package:my_ecampus/views/screens/auth_screens/login_screen.dart:60:9)
E/flutter ( 7682): <asynchronous suspension>
E/flutter ( 7682): #7 LoginScreen.build.<anonymous closure>.<anonymous closure> (package:my_ecampus/views/screens/auth_screens/login_screen.dart:198:31)
E/flutter ( 7682): #8 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:993:19)
E/flutter ( 7682): #9 _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:1111:38)
E/flutter ( 7682): #10 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:183:24)
E/flutter ( 7682): #11 TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:598:11)
E/flutter ( 7682): #12 BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:287:5)
E/flutter ( 7682): #13 BaseTapGestureRecognizer.acceptGesture (package:flutter/src/gestures/tap.dart:259:7)
E/flutter ( 7682): #14 GestureArenaManager.sweep (package:flutter/src/gestures/arena.dart:157:27)
E/flutter ( 7682): #15 GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:362:20)
E/flutter ( 7682): #16 GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:338:22)
E/flutter ( 7682): #17 RendererBinding.dispatchEvent (package:flutter/src/rendering/binding.dart:267:11)
E/flutter ( 7682): #18 GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:295:7)
E/flutter ( 7682): #19 GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:240:7)
E/flutter ( 7682): #20 GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:213:7)
E/flutter ( 7682): #21 _rootRunUnary (dart:async/zone.dart:1206:13)
E/flutter ( 7682): #22 _CustomZone.runUnary (dart:async/zone.dart:1100:19)
E/flutter ( 7682): #23 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1005:7)
E/flutter ( 7682): #24 _invoke1 (dart:ui/hooks.dart:265:10)
E/flutter ( 7682): #25 _dispatchPointerDataPacket (dart:ui/hooks.dart:174:5)
E/flutter ( 7682):
This is my main class and i am using multiprovider here.
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<WidgetProvider>(
create: (context) => WidgetProvider()),
ChangeNotifierProvider<DataProvider>(
create: (context) => DataProvider()),
],
child: MaterialApp(
home: LoginScreen(),
),
);
}
}
This is where I call getStudentData function
void _login({String email, String password, BuildContext context}) async {
final loginResponse =
await loginDatabase(email: email, password: password, context: context);
if (loginResponse.isNotEmpty) {
final isStaff = email.contains(RegExp(r'.ce#srit.org$'));
if (isStaff == true) {
getStaffData(email, context);
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (context) => StaffDashboard()));
} else {
getStudentData(email, context);//here is the getStudentData() function
Navigator.pushReplacement(context,
MaterialPageRoute(builder: (context) => StudentDashboard()));
}
} else {
print('Login Failed from loginDatabase(){}');
}
}
The HTTP request is sent to the provider listen: false because it can not listen. So that you can call the method. That's why I designed it from scratch for you. I hope you understand. It will probably work if you do it as I did.
import 'package:http/http.dart' as http;
Future<StudentData> _getStudentData(String currentEmail, BuildContext context)async {
final _url = 'https://aaa.000webhostapp.com/getStudentData.php';
final response = await http.post(_url, body: {'email': currentEmail});
var data = response.body;
if (data.isEmpty) return null;
final decodedData = jsonDecode(data);
final myRollNumber = decodedData['roll_number'];
final myFirstName = decodedData['first_name'];
final myLastName = decodedData['last_name'];
final myStudentData = StudentData(
rollNumber: myRollNumber, firstName: myFirstName, lastName: myLastName);
return MystudentData;
}
class DataProvider extends ChangeNotifier {
StudentData myStudentData;
void getMyStudentData(StudentData studentData) {
myStudentData = studentData;
notifyListeners();
}
}
Future getMyStudentDataAsync() async {
StudentData result = await _getStudentData();
getMyStudentData(result);
}
class StudentDashboard extends StatelessWidget {
#override
void initState() {
super.initState(); getRequest();
}
future getRequest()async{
Provider.of<DataProvider>(context, listen: false)
.getMyStudentDataAsync();
}
#override
Widget build(BuildContext context) {
DataProvider _dataProvider = Provider.of<DataProvider>(context);
return SafeArea(
child: Scaffold(
body: Center(
child:
Text( _dataProvider.myStudentData.rollNumber),
),
),
);
}
}

Flutter bloc_pattern returning NoSuchMethodError

I am building my first Flutter app, and foolishly enough, I started off with complex structures such as the MVVM, I don't know very much about it but have tried.
Here is my folder structure:
lib
---models
------videos.dart
---repos
------videos.dart
---viewmodels
------videos.dart
main.dart (I know)
In my main.dart file, I am using StreamBuilder to fetch the lisit of videos, here's the code:
class Home extends StatelessWidget {
VideosBloc videosBloc = BlocProvider.getBloc<VideosBloc>();
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Expanded(
flex: 1,
child: CustomAppBar(),
),
Expanded(
flex: 9,
child: Container(
color: Theme.of(context).primaryColorDark,
child: StreamBuilder(
stream: videosBloc.videosStream,
builder: (context, snapshot) {
List<Video> videos = snapshot != null ? snapshot.data : [];
return ListView(
children: videos.map((video) {
return VideoContainer(video);
}).toList(),
);
},
),
),
)
],
);
}
}
There there is this bloc file:
import 'dart:async';
import 'package:bloc_pattern/bloc_pattern.dart';
import 'package:peeke_vines/models/videos.dart';
import 'package:peeke_vines/repositories/videos.dart';
import 'package:rxdart/rxdart.dart';
class VideosBloc extends BlocBase {
VideosBloc();
//Stream that receives a number and changes the count;
var _videosController =
BehaviorSubject<List<Video>>.seeded(VideosRepo().getVideos());
//output
Stream<List<Video>> get videosStream => _videosController.stream;
//input
Sink<List<Video>> get videosSink => _videosController.sink;
//dispose will be called automatically by closing its streams
#override
void dispose() {
_videosController.close();
super.dispose();
}
}
And this bloc gets this data from a repository
import 'package:peeke_vines/models/videos.dart';
class VideosRepo {
VideosRepo();
List<Video> videos = VideoModel().fetchVideos();
List<Video> getVideos() {
return [];
}
}
And this repository currently just gets the data from a model, but later I'll implement a web service to fetch the data from:
import 'package:meta/meta.dart';
class VideoModel {
List<Video> fetchVideos() {
return [
Video(
video: 'assets/videos/main.wmv',
title: 'Peeke Vines Video Title',
date: '2 Days ago',
thumbnail: 'assets/thumbnails/1.jpg',
duration: 13.5),
Video(
video: 'assets/videos/main.wmv',
title: 'Peeke Vines Video Title',
date: '2 Days ago',
thumbnail: 'assets/thumbnails/2.jpg',
duration: 13.5),
Video(
video: 'assets/videos/main.wmv',
title: 'Peeke Vines Video Title',
date: '2 Days ago',
thumbnail: 'assets/thumbnails/1.jpg',
duration: 13.5)
];
}
}
class Video {
String video, title, date, thumbnail;
double duration;
Video(
{#required this.video,
#required this.title,
#required this.date,
#required this.thumbnail,
#required this.duration});
}
Now, whenever I import the bloc in the main.dart file using this line:
VideosBloc videosBloc = BlocProvider.getBloc<VideosBloc>();
I get this error:
I/flutter ( 4338): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter ( 4338): The following NoSuchMethodError was thrown building MyApp(dirty):
I/flutter ( 4338): Class 'NoSuchMethodError' has no instance getter 'message'.
I/flutter ( 4338): Receiver: Instance of 'NoSuchMethodError'
I/flutter ( 4338): Tried calling: message
I/flutter ( 4338):
I/flutter ( 4338): When the exception was thrown, this was the stack:
I/flutter ( 4338): #0 Object.noSuchMethod (dart:core-patch/object_patch.dart:50:5)
I/flutter ( 4338): #1 BlocProvider.getBloc (package:bloc_pattern/src/bloc_provider.dart:47:12)
I/flutter ( 4338): #2 new Home (package:peeke_vines/main.dart:35:40)
I/flutter ( 4338): #3 MyApp.build (package:peeke_vines/main.dart:21:20)
I/flutter ( 4338): #4 StatelessElement.build (package:flutter/src/widgets/framework.dart:3974:28)
I/flutter ( 4338): #5 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3924:15)
I/flutter ( 4338): #6 Element.rebuild (package:flutter/src/widgets/framework.dart:3721:5)
I/flutter ( 4338): #7 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3907:5)
I/flutter ( 4338): #8 ComponentElement.mount (package:flutter/src/widgets/framework.dart:3902:5)
I/flutter ( 4338): #9 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3084:14)
I/flutter ( 4338): #10 Element.updateChild (package:flutter/src/widgets/framework.dart:2887:12)
I/flutter ( 4338): #11 RenderObjectToWidgetElement._rebuild (package:flutter/src/widgets/binding.dart:939:16)
I/flutter ( 4338): #12 RenderObjectToWidgetElement.mount (package:flutter/src/widgets/binding.dart:910:5)
I/flutter ( 4338): #13 RenderObjectToWidgetAdapter.attachToRenderTree.<anonymous closure> (package:flutter/src/widgets/binding.dart:856:17)
I/flutter ( 4338): #14 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2320:19)
I/flutter ( 4338): #15 RenderObjectToWidgetAdapter.attachToRenderTree (package:flutter/src/widgets/binding.dart:855:13)
Can you tell me why this error is coming?
The issue is that you are trying to get the Bloc outside of the build method.
Try to get it at the start of the build method.

How to make a reusable PopupMenuButton in Flutter

I want to make a reusable PopupMenuButton in flutter, so i can call that widget and assign the PopupMenuItem dynamically.
Here is what i've done, but it throw a framework error. I am relatively new in flutter.
here is class that supposed to be reusable:
class PopupMenu {
PopupMenu({#required this.title, #required this.onTap});
final String title;
final VoidCallback onTap;
}
class PopupmMenuButtonBuilder {
setPopup(List<PopupMenu> popupItem) {
return PopupMenuButton<String>(
onSelected: (_) {
popupItem.forEach((item) => item.onTap);
},
itemBuilder: (BuildContext context) {
popupItem.forEach(
(item) {
return <PopupMenuItem<String>>[
PopupMenuItem<String>(
value: item.title,
child: Text(
item.title,
),
),
];
},
);
},
);
}
}
and then i call the widget like this:
child: PopupmMenuButtonBuilder().setPopup([
PopupMenu(title: 'Item 1', onTap: () => print('item 1 selected')),
PopupMenu(title: 'Item 2', onTap: () => print('item 2 selected')),
]),
It shows the 3 dot icon button, but when i tap the icon it throws this error:
I/flutter ( 8509): ══╡ EXCEPTION CAUGHT BY GESTURE ╞═══════════════════════════════════════════════════════════════════
I/flutter ( 8509): The following assertion was thrown while handling a gesture:
I/flutter ( 8509): 'package:flutter/src/material/popup_menu.dart': Failed assertion: line 723 pos 10: 'items != null &&
I/flutter ( 8509): items.isNotEmpty': is not true.
I/flutter ( 8509): Either the assertion indicates an error in the framework itself, or we should provide substantially
I/flutter ( 8509): more information in this error message to help you determine and fix the underlying cause.
I/flutter ( 8509): In either case, please report this assertion by filing a bug on GitHub:
I/flutter ( 8509): https://github.com/flutter/flutter/issues/new?template=BUG.md
I/flutter ( 8509): When the exception was thrown, this was the stack:
I/flutter ( 8509): #2 showMenu (package:flutter/src/material/popup_menu.dart:723:10)
I/flutter ( 8509): #3 _PopupMenuButtonState.showButtonMenu (package:flutter/src/material/popup_menu.dart:898:5)
I/flutter ( 8509): #4 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:511:14)
I/flutter ( 8509): #5 _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:566:30)
I/flutter ( 8509): #6 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:166:24)
I/flutter ( 8509): #7 TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:240:9)
I/flutter ( 8509): #8 TapGestureRecognizer.acceptGesture (package:flutter/src/gestures/tap.dart:211:7)
I/flutter ( 8509): #9 GestureArenaManager.sweep (package:flutter/src/gestures/arena.dart:156:27)
I/flutter ( 8509): #10 _WidgetsFlutterBinding&BindingBase&GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:225:20)
I/flutter ( 8509): #11 _WidgetsFlutterBinding&BindingBase&GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:199:22)
I/flutter ( 8509): #12 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:156:7)
I/flutter ( 8509): #13 _WidgetsFlutterBinding&BindingBase&GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:102:7)I/flutter ( 8509): #14 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:86:7)I/flutter ( 8509): #18 _invoke1 (dart:ui/hooks.dart:233:10)
I/flutter ( 8509): #19 _dispatchPointerDataPacket (dart:ui/hooks.dart:154:5)
I/flutter ( 8509): (elided 5 frames from class _AssertionError and package dart:async)
I/flutter ( 8509): Handler: onTap
I/flutter ( 8509): Recognizer:
I/flutter ( 8509): TapGestureRecognizer#8968f(debugOwner: GestureDetector, state: ready, won arena, finalPosition:
I/flutter ( 8509): Offset(339.0, 54.0), sent tap down)
I/flutter ( 8509): ════════════════════════════════════════════════════════════════════════════════════════════════════
Your itemBuilder needs to return a List. It doesn't actually return anything - note how the return is inside the forEach so it's just returning from the lambda. In general, forEach should sometimes be avoided. Also, the PopupMenuButtonBuilder class is redundant - it could be replaced with a static or top-level function.
One other thing that's unclear is why you want to call each onTap for every select. As you currently have it it's going to call every callback!
Try this:
class PopupMenu {
PopupMenu({#required this.title, #required this.onTap});
final String title;
final VoidCallback onTap;
static PopupMenuButton<String> createPopup(List<PopupMenu> popupItems) {
return PopupMenuButton<String>(
onSelected: (value) {
popupItems.firstWhere((e) => e.title == value).onTap();
},
itemBuilder: (context) => popupItems
.map((item) => PopupMenuItem<String>(
value: item.title,
child: Text(
item.title,
),
))
.toList(),
);
}
}
You can also create a changeable list to append to the Popup menu instead of manually creating it one by one in the child
child: PopupMenu(popUpList: _popUpList).createPopup()),
then in the Popup menu class
class PopupMenu {
const PopupMenu({this.popUpList});
final List<PopUpList> popUpList;
PopupMenuButton<String> createPopup() {
return PopupMenuButton<String>(
onSelected: (value) {
popUpList.firstWhere((e) => e.title == value).onTap();
},
itemBuilder: (context) => popUpList
.map((item) => PopupMenuItem<String>(
value: item.title,
child: Text(item.title),
)).toList(),
);
}
}
model
class PopUpList{
String title;
VoidCallback onTap;
PopUpList({this.onTap, this.title});
}
cheers!