Stream.asFuture() duplicating data when widget is refreshed - firebase

When i first load the widget it gives me an error but works as expected. When I go to another screen then back though it will duplicated the data from the future.
#override
Widget build(BuildContext context) {
final userdata = context.watch<UserDataNotifier>();
UserData data = Provider.of<UserData>(context);
double h = MediaQuery.of(context).size.height;
// print(data);
return StreamBuilder(
stream: Stream.fromFuture(data.getTheUserClasses),
builder: (context, snapshot) {
snapshot.data.toString();
return Scaffold(
backgroundColor: Color(0xff3DDC97),
appBar: AppBar(
backgroundColor: Color(0xff7211E0),
title: userdata.user == null
? CircularProgressIndicator()
: Text(userdata.user.firstName ?? ""),
),
body: Container(
// padding: EdgeInsets.symmetric(vertical: h / 8),
padding: EdgeInsets.fromLTRB(0, h / 8, 0, 0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SizedBox(
height: h * .5,
child: data.classList == null
? Loading()
: data.classList.isEmpty
? Loading()
: UserClassList(
data: data.classList,
)),
RaisedButton(
child: Text("Add Class"),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PickFromAllClasses()))
.then((value) => value ? _refresh() : null);
},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20)),
color: Colors.blue,
)
],
)),
);
},
);
}
here is how I get the data
class UserData {
String uid;
String firstName;
int rating;
List<String> classes;
List<ClassData> classList = List<ClassData>();
UserData.fromMap(Map<String, dynamic> data) {
firstName = data['firstname'] ?? "";
rating = data['rating'] ?? "";
classes = data['classes'].cast<String>() ?? "";
}
List<ClassData> get cs => classList;
set cs(List<ClassData> s) {
cs = s;
}
Future get getTheUserClasses async {
for (String c in classes) {
DocumentSnapshot classsnapshot =
await Firestore.instance.collection("Classes").document(c).get();
final data =
ClassData.fromUserMap(classsnapshot.data, classsnapshot.documentID);
if (data != null) {
classList.add(data);
// print(data.classdescription);
}
}
cs = classList;
}
UserData({this.firstName, this.rating, this.classes});
}
Here is the error I get when I load this widget.
flutter: ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
flutter: The following NoSuchMethodError was thrown building YourClasses(dirty, dependencies: [MediaQuery,
flutter: _InheritedProviderScope<UserDataNotifier>, _InheritedProviderScope<UserData>], state:
flutter: _YourClassesState#4bf6d):
flutter: The getter 'getTheUserClasses' was called on null.
flutter: Receiver: null
flutter: Tried calling: getTheUserClasses
flutter:
flutter: The relevant error-causing widget was:
flutter: YourClasses
flutter: file:///Users/devintripp/Desktop/flutter_apps.no_sync/discoverytutors/lib/Screens/LoggedIn/TutorsView/tutors.dart:148:65
flutter:
flutter: When the exception was thrown, this was the stack:
flutter: #0 Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5)
flutter: #1 _YourClassesState.build (package:disc_t/Screens/LoggedIn/Classes/yourclasses.dart:66:38)
flutter: #2 StatefulElement.build (package:flutter/src/widgets/framework.dart:4619:28)
flutter: #3 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4502:15)
flutter: #4 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4675:11)
flutter: #5 Element.rebuild (package:flutter/src/widgets/framework.dart:4218:5)
flutter: #6 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4481:5)
flutter: #7 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:4666:11)
flutter: #8 ComponentElement.mount (package:flutter/src/widgets/framework.dart:4476:5)
flutter: ... Normal element mounting (24 frames)
flutter: #32 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3446:14)
flutter: #33 MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:5947:32)
flutter: ... Normal element mounting (119 frames)
flutter: #152 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3446:14)
flutter: #153 Element.updateChild (package:flutter/src/widgets/framework.dart:3214:18)
flutter: #154 RenderObjectElement.updateChildren (package:flutter/src/widgets/framework.dart:5580:32)
flutter: #155 MultiChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:5957:17)
flutter: #156 Element.updateChild (package:flutter/src/widgets/framework.dart:3201:15)
flutter: #157 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4527:16)
flutter: #158 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4675:11)
flutter: #159 Element.rebuild (package:flutter/src/widgets/framework.dart:4218:5)
flutter: #160 StatefulElement.update (package:flutter/src/widgets/framework.dart:4707:5)
flutter: #161 Element.updateChild (package:flutter/src/widgets/framework.dart:3201:15)
flutter: #162 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4527:16)
flutter: #163 Element.rebuild (package:flutter/src/widgets/framework.dart:4218:5)
flutter: #164 ProxyElement.update (package:flutter/src/widgets/framework.dart:4862:5)
flutter: #165 _InheritedNotifierElement.update (package:flutter/src/widgets/inherited_notifier.dart:181:11)
flutter: #166 Element.updateChild (package:flutter/src/widgets/framework.dart:3201:15)
flutter: #167 SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:5837:14)
flutter: #168 Element.updateChild (package:flutter/src/widgets/framework.dart:3201:15)
flutter: #169 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4527:16)
flutter: #170 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4675:11)
flutter: #171 Element.rebuild (package:flutter/src/widgets/framework.dart:4218:5)
flutter: #172 StatefulElement.update (package:flutter/src/widgets/framework.dart:4707:5)
flutter: #173 Element.updateChild (package:flutter/src/widgets/framework.dart:3201:15)
flutter: #174 SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:5837:14)
flutter: #175 Element.updateChild (package:flutter/src/widgets/framework.dart:3201:15)
flutter: #176 SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:5837:14)
flutter: #177 Element.updateChild (package:flutter/src/widgets/framework.dart:3201:15)
flutter: #178 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4527:16)
flutter: #179 Element.rebuild (package:flutter/src/widgets/framework.dart:4218:5)
flutter: #180 StatelessElement.update (package:flutter/src/widgets/framework.dart:4583:5)
flutter: #181 Element.updateChild (package:flutter/src/widgets/framework.dart:3201:15)
flutter: #182 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4527:16)
flutter: #183 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4675:11)
flutter: #184 Element.rebuild (package:flutter/src/widgets/framework.dart:4218:5)
flutter: #185 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2627:33)
flutter: #186 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:883:20)
flutter: #187 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:284:5)
flutter: #188 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1113:15)
flutter: #189 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1052:9)
flutter: #190 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:968:5)
flutter: #194 _invoke (dart:ui/hooks.dart:261:10)
flutter: #195 _drawFrame (dart:ui/hooks.dart:219:3)
flutter: (elided 3 frames from dart:async)
Here is the screen that is loaded at first.
then when it duplicates it gets the same data 3 times. This is after i refresh this widget.

Instead of using a StreamBuilder, use a FutureBuilder.
Instead of creating your Future on every build, create the Future once and save it to a variable in your state, so it does not get called again and again, but only once, no matter how many times your build method is called.

Stream.fromFuture() does not cover your use case. It will not update if new elements are added or elements are deleted (since it just gets the elements from a Future).
In your case you might want to do something like the following:
Stream<List<YourModel>> getUserList() {
return Firestore.instance.collection('Classes')
.snapshots()
.map((snapShot) => snapShot.documents
.map((document) => Yourmodel.fromDocument(document.data)
.toList());
}
Furthermore, in order to avoid the error you see in the console, you need to check whether the document has data (e.g. if (document.hasData())) and return the widget to be displayed if no data is available yet.

Related

Unhandled Exception: Failed assertion: boolean expression must not be null when using Firebase.initializeApp()

I am creating a Flutter application that uses Firebase. I keep getting an error when trying to use Firebase.initializeApp().
main.dart
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:myapp/screens/home/home.dart';
import 'package:myapp/screens/landing/landing.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context){
Future<User> currentUser = FirebaseAuth.instance.currentUser as Future<User>;
return FutureBuilder<User>(
future: currentUser,
builder: (BuildContext context, AsyncSnapshot<User> snapshot){
if (snapshot.hasData){
User user = snapshot.data;
return HomeScreen();
}
return LandingScreen();
}
);
}
}
Error
E/flutter (31443): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: Failed assertion: boolean expression must not be null
E/flutter (31443): #0 new FirebaseOptions.fromMap (package:firebase_core_platform_interface/src/firebase_options.dart:78:47)
E/flutter (31443): #1 MethodChannelFirebase._initializeFirebaseAppFromMap (package:firebase_core_platform_interface/src/method_channel/method_channel_firebase.dart:44:23)
E/flutter (31443): #2 ListMixin.forEach (dart:collection/list.dart:86:13)
E/flutter (31443): #3 MethodChannelFirebase._initializeCore (package:firebase_core_platform_interface/src/method_channel/method_channel_firebase.dart:34:10)
E/flutter (31443): <asynchronous suspension>
E/flutter (31443): #4 MethodChannelFirebase.initializeApp (package:firebase_core_platform_interface/src/method_channel/method_channel_firebase.dart:75:13)
E/flutter (31443): #5 Firebase.initializeApp (package:firebase_core/src/firebase.dart:43:25)
E/flutter (31443): #6 main (package:myapp/main.dart:12:18)
E/flutter (31443): #7 _runMainZoned.<anonymous closure>.<anonymous closure> (dart:ui/hooks.dart:231:25)
E/flutter (31443): #8 _rootRun (dart:async/zone.dart:1190:13)
E/flutter (31443): #9 _CustomZone.run (dart:async/zone.dart:1093:19)
E/flutter (31443): #10 _runZoned (dart:async/zone.dart:1630:10)
E/flutter (31443): #11 runZonedGuarded (dart:async/zone.dart:1618:12)
E/flutter (31443): #12 _runMainZoned.<anonymous closure> (dart:ui/hooks.dart:223:5)
E/flutter (31443): #13 _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:301:19)
E/flutter (31443): #14 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:168:12)
E/flutter (31443):
My main.dart line 12 is Firebase.initializeApp()
What am I missing?
pubspec.yaml
name: myapp
description: Myapp
version: 1.0.0+1
environment:
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
cloud_firestore: ^0.14.4
firebase_auth: ^0.18.4+1
firebase_core: 0.5.3
cupertino_icons: ^1.0.0
dev_dependencies:
flutter_test:
sdk: flutter
flutter:
uses-material-design: true
Update
I have been able to get around the error by entirely changing my structure of main.dart like below. This was taken from a Flutter example:
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// Create the initialization Future outside of `build`:
final Future<FirebaseApp> _initialization = Firebase.initializeApp();
#override
Widget build(BuildContext context) {
return FutureBuilder(
// Initialize FlutterFire:
future: _initialization,
builder: (context, snapshot) {
// Check for errors
if (snapshot.hasError) {
return MaterialApp(
title: 'MyApp',
home: LandingScreen(),
);
}
// Once complete, show your application
if (snapshot.connectionState == ConnectionState.done) {
return MaterialApp(
title: 'MyApp',
home: LandingScreen(),
);
}
// Otherwise, show something whilst waiting for initialization to complete
return MaterialApp(
title: 'MyApp',
home: LandingScreen(),
);
},
);
}
}
While this does seem to work, I would still love to know why the other structure was not working, when it seems that the other structure is what is recommended in most docs.

Getting error when using multiprovider and consumer in flutter

I recently updated firebase dependencies. I do not recommend this, by the way, I am having an awful experience. Google can't figure out what naming conventions to go by.
after updating and fixing all of the errors they caused I tried to run my app and got the initialize firebase error. Well after that error was mitigated I seem to have run into an error I cannot solve.
Here is the relevant code.
Widget build(BuildContext context) {
return StreamProvider<UserTutor>.value(
value: AuthService().user,
child: Consumer<UserTutor>(
builder: (_, user, __) {
return MultiProvider(
providers: [
user == null
? StreamProvider<Tutor>.value(
value: DatabaseService().streamTutor,
)
: StreamProvider<Tutor>.value(
value: DatabaseService(uid: user.uid).streamTutor,
),
user == null
? StreamProvider<List<ClassData>>.value(
value: DatabaseService().classdata)
: StreamProvider<List<ClassData>>.value(
value: DatabaseService(uid: user.uid).classdata),
],
child: MaterialApp(
home: Wrapper(),
debugShowCheckedModeBanner: false,
),
);
},
));
}
final FirebaseAuth _auth = FirebaseAuth.instance;
final GoogleSignIn googleSignIn = GoogleSignIn();
//create user obj based on firebase user
UserTutor _userFromFirebaseUser(User user) {
return user != null ? UserTutor(uid: user.uid, email: user.email) : null;
}
//auth change user stream
Stream<UserTutor> get user {
return _auth
.authStateChanges()
.map((User user) => _userFromFirebaseUser(user));
}
and here is the error I am receiving.
flutter: ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
flutter: The following assertion was thrown building Consumer<UserTutor>(dirty, dependencies:
flutter: [_InheritedProviderScope<UserTutor>]):
flutter: a collection path must point to a valid collection.
flutter: 'package:cloud_firestore/src/firestore.dart':
flutter: Failed assertion: line 74 pos 12: 'isValidCollectionPath(collectionPath)'
flutter:
flutter: The relevant error-causing widget was:
flutter: Consumer<UserTutor>
flutter: file:///Users/devintripp/Desktop/flutter_apps.no_sync/discoverytutors/lib/main.dart:25:16
flutter:
flutter: When the exception was thrown, this was the stack:
flutter: #2 FirebaseFirestore.collection (package:cloud_firestore/src/firestore.dart:74:12)
flutter: #3 new DatabaseService (package:disc_t/Services/database.dart:19:34)
flutter: #4 MyApp.build.<anonymous closure> (package:disc_t/main.dart:37:32)
flutter: #5 Consumer.buildWithChild (package:provider/src/consumer.dart:175:19)
flutter: #6 SingleChildStatelessWidget.build (package:nested/nested.dart:260:41)
flutter: #7 StatelessElement.build (package:flutter/src/widgets/framework.dart:4620:28)
flutter: #8 SingleChildStatelessElement.build (package:nested/nested.dart:280:18)
flutter: #9 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4546:15)
flutter: #10 Element.rebuild (package:flutter/src/widgets/framework.dart:4262:5)
flutter: #11 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4525:5)
flutter: #12 ComponentElement.mount (package:flutter/src/widgets/framework.dart:4520:5)
flutter: #13 SingleChildWidgetElementMixin.mount (package:nested/nested.dart:223:11)
flutter: #14 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3490:14)
flutter: #15 Element.updateChild (package:flutter/src/widgets/framework.dart:3258:18)
flutter: #16 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4571:16)
flutter: #17 _InheritedProviderScopeElement.performRebuild (package:provider/src/inherited_provider.dart:426:11)
flutter: #18 Element.rebuild (package:flutter/src/widgets/framework.dart:4262:5)
flutter: #19 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4525:5)
flutter: #20 ComponentElement.mount (package:flutter/src/widgets/framework.dart:4520:5)
flutter: ... Normal element mounting (7 frames)
flutter: #27 SingleChildWidgetElementMixin.mount (package:nested/nested.dart:223:11)
flutter: ... Normal element mounting (7 frames)
flutter: #34 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3490:14)
flutter: #35 Element.updateChild (package:flutter/src/widgets/framework.dart:3258:18)
flutter: #36 RenderObjectToWidgetElement._rebuild (package:flutter/src/widgets/binding.dart:1174:16)
flutter: #37 RenderObjectToWidgetElement.mount (package:flutter/src/widgets/binding.dart:1145:5)
flutter: #38 RenderObjectToWidgetAdapter.attachToRenderTree.<anonymous closure> (package:flutter/src/widgets/binding.dart:1087:17)
flutter: #39 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2620:19)
flutter: #40 RenderObjectToWidgetAdapter.attachToRenderTree (package:flutter/src/widgets/binding.dart:1086:13)
flutter: #41 WidgetsBinding.attachRootWidget (package:flutter/src/widgets/binding.dart:927:7)
flutter: #42 WidgetsBinding.scheduleAttachRootWidget.<anonymous closure> (package:flutter/src/widgets/binding.dart:908:7)
flutter: (elided 13 frames from class _AssertionError, class _RawReceivePortImpl, class _Timer, dart:async, and dart:async-patch)
flutter:

Flutter - A non-null String must be provided to a Text widget

I am having an error as regards fetching data from firestore using futureBuilder. When I do a print of snapshot.data without calling a Text widget, I get an instance of 'User'.
Without Calling author.fullname
body: ListView.builder(
itemCount: _posts.length,
itemBuilder: (BuildContext context, int index) {
Post post = _posts[index];
return FutureBuilder(
future: DatabaseService.getUserWithId(post.authorid),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasData) {
print(snapshot.data);
User author = snapshot.data;
return Column(
children: <Widget>[],
);
}
}
return SizedBox.shrink();
Output
Performing hot restart...
Restarted application in 1,146ms.
flutter: Instance of 'User'
flutter: Instance of 'User'
However when I try to call for the fullname of the user from firestore, it returns null
body: ListView.builder(
itemCount: _posts.length,
itemBuilder: (BuildContext context, int index) {
Post post = _posts[index];
return FutureBuilder(
future: DatabaseService.getUserWithId(post.authorid),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasData) {
print(snapshot.data);
User author = snapshot.data;
return Column(
children: <Widget>[
Text(author.fullname)
],
);
}
}
return SizedBox.shrink();
Output
Performing hot restart...
Restarted application in 1,042ms.
flutter: Instance of 'User'
flutter: ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY
flutter: The following assertion was thrown building FutureBuilder<User>(dirty, state:
flutter: _FutureBuilderState<User>#23d74):
flutter: A non-null String must be provided to a Text widget.
flutter: 'package:flutter/src/widgets/text.dart':
flutter: Failed assertion: line 285 pos 10: 'data != null'
flutter:
flutter: Either the assertion indicates an error in the framework itself, or we should provide substantially
flutter: more information in this error message to help you determine and fix the underlying cause.
flutter: In either case, please report this assertion by filing a bug on GitHub:
flutter: https://github.com/flutter/flutter/issues/new?template=BUG.md
flutter:
flutter: The relevant error-causing widget was:
flutter: FutureBuilder<User> file:///Users/momo/Desktop/combine/lib/screens/home.dart:65:18
flutter:
flutter: When the exception was thrown, this was the stack:
flutter: #2 new Text (package:flutter/src/widgets/text.dart:285:10)
flutter: #3_HomeState.build.<anonymous closure>.<anonymous closure> (package:combine/screens/home.dart:75:23)
flutter: #4 _FutureBuilderState.build (package:flutter/src/widgets/async.dart)
flutter: #5 StatefulElement.build (package:flutter/src/widgets/framework.dart:4334:27)
flutter: #6 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4223:15)
flutter: #7 Element.rebuild (package:flutter/src/widgets/framework.dart:3947:5)
flutter: #8 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2432:33)
flutter: #9 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:773:20)
flutter: #10 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:283:5)
flutter: #11 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1102:15)
flutter: #12 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1041:9)
flutter: #13 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:957:5)
flutter: #17 _invoke (dart:ui/hooks.dart:259:10)
flutter: #18 _drawFrame (dart:ui/hooks.dart:217:3)
flutter: (elided 5 frames from class _AssertionError and package dart:async)
User Class
class User {
final String id;
final String email;
final String password;
final String fullname;
User(
{this.id,
this.email,
this.password,
this.fullname,});
factory User.fromDoc(DocumentSnapshot doc) {
return User(
id: doc.documentID,
email: doc['email'],
fullname: doc['fullname'],
);
}
}
You must provide an empty text in case the name is null
return Column(
children: <Widget>[
Text(author.fullname == null? '' : author.fullname)
],
);

Flutter NoSuchMethodError was thrown building FutureBuilder<DocumentSnapshot>

I am getting this error while trying to fetch user data from the cloud_firestore but it's only getting me this error when for the first time, users login to the app and navigate to the profile screen. if I hot restart or rerun the app, while in login state error goes away.
flutter: ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══
flutter: The following NoSuchMethodError was thrown building StreamBuilder<DocumentSnapshot>(dirty, state:
flutter: _StreamBuilderBaseState<DocumentSnapshot, AsyncSnapshot<DocumentSnapshot>>#f33a1):
flutter: The method '[]' was called on null.
flutter: Receiver: null
flutter: Tried calling: []("name")
flutter:
flutter: User-created ancestor of the error-causing widget was:
flutter: SliverFillRemaining
flutter: file:///Users/ishangavidusha/Development/MUD/mud_mobile_app/lib/screens/profile_screen.dart:102:13
flutter:
flutter: When the exception was thrown, this was the stack:
flutter: #0 Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)
flutter: #1 new User.from (package:mud_mobile_app/models/user_model.dart:23:22)
flutter: #2 _ProfileScreenState.build.<anonymous closure> (package:mud_mobile_app/screens/profile_screen.dart:107:38)
flutter: #3 StreamBuilder.build (package:flutter/src/widgets/async.dart:425:74)
flutter: #4 _StreamBuilderBaseState.build (package:flutter/src/widgets/async.dart:125:48)
flutter: #5 StatefulElement.build (package:flutter/src/widgets/framework.dart:4047:27)
flutter: #6 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3941:15)
flutter: #7 Element.rebuild (package:flutter/src/widgets/framework.dart:3738:5)
flutter: #8 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2348:33)
flutter: #9 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:760:20)
flutter: #10 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:280:5)
flutter: #11 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1033:15)
flutter: #12 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:975:9)
flutter: #13 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:891:5)
flutter: #17 _invoke (dart:ui/hooks.dart:249:10)
flutter: #18 _drawFrame (dart:ui/hooks.dart:207:3)
flutter: (elided 3 frames from package dart:async)
Emulator Screenshot
And this is the user model I use >
class User {
final String id;
final String name;
final String profileImageUrl;
final String email;
User({this.id, this.name, this.profileImageUrl, this.email});
factory User.fromDoc(DocumentSnapshot doc) {
return User(
id: doc.documentID,
name: doc['name'],
profileImageUrl: doc['profileImageUrl'],
email: doc['email'],
);
}
}
FutureBuilder >
SliverFillRemaining(
child: FutureBuilder(
future: _getUserData(widget.userId),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return Padding(
padding: const EdgeInsets.all(50.0),
child: Center(
child: CircularProgressIndicator(),
),
);
}
User user = User.fromDoc(snapshot.data);
return Column(
children: <Widget>[
Padding(...),
Container(...),
Container(...),
],
);
}
)
)
And the Funtion DocumentSnapshot return >
Future<DocumentSnapshot> _getUserData(userId) async {
return Firestore.instance.collection('users').document(userId).get();
}
"StreamBuilder dirty state" warnings are usually shown if the snapshot data doesn't have a safety check. This ensures that the snapshot contains data. However, it seems if (!snapshot.hasData) is set as a safety check on the snippet you've provided.
From the details you've given, the error seems to only occur during first user login, but the error goes away on hot restart or app restart. I suggest checking if the method _getUserData(String userId) is able to receive the userId upon the first user login where the error usually occurs. Null seems to be passed on where the error occurs based from the logs you've provided.
flutter: The method '[]' was called on null.
flutter: Receiver: null
flutter: Tried calling: []("name")
FutureBuilder<DocumentSnapshot>(
future: users.doc(documentId).get(),
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) {
return Text("Something went wrong");
}
if (snapshot.hasData && !snapshot.data!.exists) {
return Text("Document does not exist");
}
if (snapshot.connectionState == ConnectionState.done) {
Map<String, dynamic> data = snapshot.data!.data() as Map<String, dynamic>;
return Text("Full Name: ${data['full_name']} ${data['last_name']}");
}
return Text("loading");
If you are using above similar type code and then get same error , check the firebase documentId in collection name and snapshot

Flutter setState() or markNeedsBuild() called when widget tree was locked

I am having trouble finding the source to this exception, and the app is quite complex so it is hard to show any relevant part of the code. This is my repository at the point where the error happens:
Github repo
I suspect the following code might be the perpetrator:
Widget buildResultCard(Map result, BuildContext context) {
String name = result["value"];
String description =
result["label"].replaceAll(new RegExp(r"<(?:.|\n)*?>"), "");
TextEditingController controller = new TextEditingController(text: name);
Function onPressed = () {
showDialog(
context: context,
child: new AlertDialog(
title: new Text("Name your schedule"),
content: new TextField(
autofocus: true,
controller: controller,
),
actions: <Widget>[
new FlatButton(
onPressed: () {
String givenName = controller.text;
ScheduleMeta schedule = new ScheduleMeta(
givenName: givenName,
name: name,
type: _selectedChoice.value,
description: description);
scheduleStore
.dispatch(new AddScheduleAction(schedule: schedule));
scheduleStore.dispatch(
new SetCurrentScheduleAction(schedule: schedule));
fetchAllSchedules(scheduleStore.state.schedules)
.then((weeks) {
scheduleStore.dispatch(
new SetWeeksForCurrentScheduleAction(weeks: weeks));
});
Scaffold.of(context).showSnackBar(new SnackBar(
content: new Text("Added " + givenName),
action: new SnackBarAction(
label: "Undo",
onPressed: () {
scheduleStore.dispatch(
new RemoveScheduleAction(schedule: name));
Scaffold.of(context).showSnackBar(new SnackBar(
content: new Text(
"Deleted " + givenName),
));
}),
));
Navigator.of(context).pop();
},
child: new Text("Add")),
],
));
};
return new Card(
child: new Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new ListTile(
leading: const Icon(Icons.schedule),
title: new Text(name),
subtitle: new Text(description),
isThreeLine: true,
dense: true,
),
new ButtonTheme.bar(
child: new ButtonBar(
children: <Widget>[
new FlatButton(
child: const Text('Add Schedule'),
onPressed: scheduleStore.state.schedules
.any((schedule) => schedule.name == name)
? null
: onPressed)
],
),
),
],
),
);
}
The error appears when showing a dialog, and when the user presses a button on the dialog, two Redux store dispatches are sent directly after each other. The UI behind the dialog subscribes to changes in the Redux store.
I thought Dart/Flutter was single-threaded so no collision like this could happen, where it seems like a thread is calling setState() on a widget while another has put a lock on the widget tree.
Is there a way of checking if the widget tree is locked so this can be avoided?
The stack provides this info:
I/flutter (13466): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter (13466): The following assertion was thrown while finalizing the widget tree:
I/flutter (13466): setState() or markNeedsBuild() called when widget tree was locked.
I/flutter (13466): This _ModalScope widget cannot be marked as needing to build because the framework is locked.
I/flutter (13466): The widget on which setState() or markNeedsBuild() was called was:
I/flutter (13466): _ModalScope([LabeledGlobalKey<_ModalScopeState>#cb4cc]; state: _ModalScopeState#d4c02())
I/flutter (13466):
I/flutter (13466): When the exception was thrown, this was the stack:
I/flutter (13466): #0 Element.markNeedsBuild.<anonymous closure> (package:flutter/src/widgets/framework.dart:3250)
I/flutter (13466): #2 Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:3226)
I/flutter (13466): #3 State.setState (package:flutter/src/widgets/framework.dart:1072)
I/flutter (13466): #4 _ModalScopeState._routeSetState (package:flutter/src/widgets/routes.dart:473)
I/flutter (13466): #5 ModalRoute.setState (package:flutter/src/widgets/routes.dart:552)
I/flutter (13466): #6 ModalRoute.changedInternalState (package:flutter/src/widgets/routes.dart:889)
I/flutter (13466): #7 TransitionRoute&&LocalHistoryRoute.removeLocalHistoryEntry (package:flutter/src/widgets/routes.dart:317)
I/flutter (13466): #8 LocalHistoryEntry.remove (package:flutter/src/widgets/routes.dart:267)
I/flutter (13466): #9 DrawerControllerState.dispose (package:flutter/src/material/drawer.dart:147)
I/flutter (13466): #10 StatefulElement.unmount (package:flutter/src/widgets/framework.dart:3550)
I/flutter (13466): #11 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1626)
I/flutter (13466): #12 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1624)
I/flutter (13466): #13 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3427)
I/flutter (13466): #14 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1622)
I/flutter (13466): #15 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1624)
I/flutter (13466): #16 MultiChildRenderObjectElement.visitChildren (package:flutter/src/widgets/framework.dart:4421)
I/flutter (13466): #17 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1622)
I/flutter (13466): #18 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1624)
I/flutter (13466): #19 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3427)
I/flutter (13466): #20 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1622)
I/flutter (13466): #21 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1624)
I/flutter (13466): #22 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3427)
I/flutter (13466): #23 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1622)
I/flutter (13466): #24 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1624)
I/flutter (13466): #25 SingleChildRenderObjectElement.visitChildren (package:flutter/src/widgets/framework.dart:4321)
I/flutter (13466): #26 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1622)
I/flutter (13466): #27 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1624)
I/flutter (13466): #28 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3427)
I/flutter (13466): #29 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1622)
I/flutter (13466): #30 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1624)
I/flutter (13466): #31 SingleChildRenderObjectElement.visitChildren (package:flutter/src/widgets/framework.dart:4321)
I/flutter (13466): #32 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1622)
I/flutter (13466): #33 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1624)
I/flutter (13466): #34 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3427)
I/flutter (13466): #35 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1622)
I/flutter (13466): #36 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1624)
I/flutter (13466): #37 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3427)
I/flutter (13466): #38 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1622)
I/flutter (13466): #39 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1624)
I/flutter (13466): #40 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3427)
I/flutter (13466): #41 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1622)
I/flutter (13466): #42 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1624)
I/flutter (13466): #43 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3427)
I/flutter (13466): #44 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1622)
I/flutter (13466): #45 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1624)
I/flutter (13466): #46 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3427)
I/flutter (13466): #47 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1622)
I/flutter (13466): #48 _InactiveElements._unmountAll (package:flutter/src/widgets/framework.dart:1636)
I/flutter (13466): #49 BuildOwner.finalizeTree.<anonymous closure> (package:flutter/src/widgets/framework.dart:2228)
I/flutter (13466): #50 BuildOwner.lockState (package:flutter/src/widgets/framework.dart:2060)
I/flutter (13466): #51 BuildOwner.finalizeTree (package:flutter/src/widgets/framework.dart:2227)
I/flutter (13466): #52 BindingBase&SchedulerBinding&GestureBinding&ServicesBinding&RendererBinding&WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:505)
I/flutter (13466): #53 BindingBase&SchedulerBinding&GestureBinding&ServicesBinding&RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:189)
I/flutter (13466): #54 BindingBase&SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:688)
I/flutter (13466): #55 BindingBase&SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:636)
I/flutter (13466): #56 _drawFrame (file:///b/build/slave/Linux_Engine/build/src/flutter/lib/ui/hooks.dart:70)
I/flutter (13466): (elided one frame from class _AssertionError)
I/flutter (13466): ════════════════════════════════════════════════════════════════════════════════════════════════════
As a workaround wrap your code that calling setState into WidgetsBinding.addPostFrameCallback:
WidgetsBinding.instance
.addPostFrameCallback((_) => setState(() {}));
That way you can be sure it gets executed after the current widget is built.
Special case of using Scaffold and Drawer:
That fail can also happen if you try to rebuild the tree with opened Drawer. For example if you send a message to a Bloc that forces rebuilding of the whole page/screen.
Consider to call Navigator.pop(context) first in your tap handler.
This is not a thread problem. This error means that you are calling setState during the build phase.
A typical example would be the following :
Widget build(BuildContext context) {
myParentWidgetState.setState(() { print("foo"); });
return Container();
}
But the setState call may be less obvious. For example a Navigator.pop(context) does a setState internally. So the following :
Widget build(BuildContext context) {
Navigator.pop(context);
return Container();
}
is a no go either.
Looking at the stacktrace it seems that simultaneously with the Navigator.pop(context) your modal try to update with new data.
As the provided answer seems true, I had a work around as, in my case, it was not possible to simply remove it from the build.
I used Future.delayed(Duration.zero, () => setState(() { ... })); instead of setState and the same for methods that may use setState as well.
EDIT: source
There are couple of options used setState inside build method and context on initState
Wrap your setState inside one of these
WidgetsBinding.instance.addPostFrameCallback or Future.microTask() or Timer.run or Future.delayed(Duration.zero,
Example:
WidgetsBinding.instance
.addPostFrameCallback((_) {
//valueNotifier.value = _pcm; //provider
//setState
});
I faced the same issue when making a widget that need to do Navigator.pop before returning an Widget in build.
Let me call the code from Rémi Rousselet:
Widget build(BuildContext context) {
Navigator.pop(context);
return Container();
}
This code above would cause the error, but you could only pop becasue context is in build, so how to do?
Widget build(BuildContext context) {
if(datas != null) // check datas
{
SchedulerBinding.instance.addPostFrameCallback((_){ // make pop action to next cycle
Navigator.of(context).pop(datas); /*...your datas*/
});
}
return Container();
}
This method is the combination of the others, but I'm not sure If this is the best practice, If there are any errors, please leave a comment to point me out!
Use Timer class,
import 'dart:async';
#override
void initState() {
super.initState();
Timer.run(() {
// You can call setState from here
});
}
I control user at LoginScreen on every opening or reload. If user is authenticated i navigate to home. At this point i get same error. It's about navigator's own setState as i understood. addPostFrameCallback or timer fix it.
void initState() {
super.initState();
if (auth.getUser != null) {
// ERROR
// Navigator.pushReplacementNamed(context, '/home');
// SUCCESS
// WidgetsBinding.instance.addPostFrameCallback((_) => setState(() {
// Navigator.pushReplacementNamed(context, '/home');
// }));
// SUCCESS
Timer.run(() {
Navigator.pushReplacementNamed(context, '/home');
});
}
}
void initState() {
super.initState();
if (auth.getUser != null) {
// ERROR
// Navigator.pushReplacementNamed(context, '/home');
// SUCCESS
// WidgetsBinding.instance.addPostFrameCallback((_) => setState(() {
// Navigator.pushReplacementNamed(context, '/home');
// }));
// SUCCESS
Timer.run(() {
Navigator.pushReplacementNamed(context, '/home');
});
}
}

Resources