Flutter Unhandled Exception: setState() called in constructor: - flutter

I am trying to create an application to display route and location pointer while executing getting this error.
HomePage.dart:
class _MapState extends State<Map> {
///////////body of statements///////////
void _addMarker(LatLng location){
setState(() {
_markers.add(Marker(markerId: MarkerId(location.toString()),
position: location,
icon: BitmapDescriptor.defaultMarker,
));
});
}
void createRoute(String encodedPoly){
setState(() {
_polyLines.add(Polyline(polylineId: PolylineId(_lastPosition.toString()),
width: 10,
points: _convertToLatLng(googleMapsServices.decodePoly(encodedPoly)),
color: black,
));
});
}
}
This is inherited class placed in HomePage.dart:
class sendReq extends _MapState{
void sendRequest(String intendedLocation)async{
super.initState();
List<Placemark> placemark = await Geolocator().placemarkFromAddress(intendedLocation);
double latitude = placemark[0].position.latitude;
double longitude = placemark[0].position.longitude;
LatLng destination = LatLng(latitude,longitude);
print("The intended location is $intendedLocation with the LatLang of $destination");
_addMarker(destination);
String route = await googleMapsServices.getRouteCoordinates(_lastPosition, destination);
createRoute(route);
}
}
This is location.dart page:
onSubmitted: (value){
sr.sendRequest(value);
},
While running this code on location input it gives this error:
E/flutter (12680): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: setState() called in constructor: sendReq#c5316(lifecycle state: created, no widget, not mounted)
E/flutter (12680): This happens when you call setState() on a State object for a widget that hasn't been inserted into the widget tree yet. It is not necessary to call setState() in the constructor, since the state is already assumed to be dirty when it is initially created.

You should not call setState() before the build completed,
use WidgetsBinding.addPostFrameCallback()
like this.....
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
//executes after build is done
})
}
hope you get the idea...

Related

Unhandled Exception: setState() called after dispose() with Firebase Realtime Database chat feature

I am receiving this error:
[VERBOSE-2:dart_vm_initializer.cc(41)] Unhandled Exception: setState() called after dispose(): _EventChatScreenState#7c8b5(lifecycle state: defunct, not mounted)
This error happens if you call setState() on a State object for a widget that no longer appears in the widget tree (e.g., whose parent widget no longer includes the widget in its build). This error can occur when code calls setState() from a timer or an animation callback.
The preferred solution is to cancel the timer or stop listening to the animation in the dispose() callback. Another solution is to check the "mounted" property of this object before calling setState() to ensure the object is still in the tree.
This error might indicate a memory leak if setState() is being called because another object is retaining a reference to this State object after it has been removed from the tree. To avoid memory leaks, consider breaking the reference to this object during dispose().
#0 State.setState.<anonymous closure> (package:flutter/src/wid<…>
However, the only place I am calling setState is in the initState:
#override
void initState() {
super.initState();
dbRef = dbInstance.ref("/events/");
var query = dbRef!.child(widget.event.event.eventId);
FirebaseList(
query: query,
onChildAdded: (index, snapshot) {
Map<dynamic, dynamic> childMap = snapshot.value as dynamic;
ChatMessage newChatMessage = ChatMessage(
chatMessageId: snapshot.key.toString(),
userId: childMap["userId"],
displayName: childMap["displayName"],
message: childMap["message"],
datetime: childMap["datetime"],
);
setState(() {
chatMessages.add(newChatMessage);
});
},
);
_messageFieldController = TextEditingController();
}
#override
void dispose() {
super.dispose();
_messageFieldController.dispose();
}
I'm not really sure why this is happening, but I included the dispose method since it the error references it.
Worth noting that I am doing this to make the screen scroll to the bottom of the chat messages which are display using a ListView.builder
void scrollToBottom() {
SchedulerBinding.instance.addPostFrameCallback((_) {
_scrollController.jumpTo(_scrollController.position.maxScrollExtent);
});
}
#override
Widget build(BuildContext context) {
final user = ref.watch(userProvider);
if (chatMessages.isNotEmpty) {
scrollToBottom();
}
If I remove the above code the issue seems to go away
instead of this
#override
void dispose() {
super.dispose();
_messageFieldController.dispose();
}
try this
#override
void dispose() {
_messageFieldController.dispose();
super.dispose();
}

Geolocator, setState, memory leak

I'm working on geolocation with geolocation 7.6.2 package. I have a problem with memory leak when closing the stream. Widget looks like this:
class _GeolocatorActiveState extends State<GeolocatorActive> {
StreamSubscription<Position>? _currentPosition;
double distanceToday = 0.0;
double distanceTotal = 0.0;
bool gpsActive = true;
#override
void initState() {
getCurrentPosition();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
// Some stuff
),
),
backgroundColor: Colors.deepOrange
),
body: Column(
children: [
// some stuff here
TextButton(onPressed: () {
setState(() {
gpsActive = false;
stopStream();
});
Navigator.pushNamed(context, '/');},
child: Text(
'Finish',
)
),
// Some stuff there
],
),
);
}
void getCurrentPosition () {
final positionStream = GeolocatorPlatform.instance.getPositionStream();
if(gpsActive == true){
_currentPosition = positionStream.listen((position) {
setState(() {
long = position.longitude.toString();
lat = position.latitude.toString();
});
});
}
}
void stopStream () {
_currentPosition = null;
_currentPosition?.cancel();
super.dispose();
}
}
Now, the thing is that when I push the button "Finish" I want to close and remove this Widget. I tried with Navigator.pushNamedAndRemoveUntil and thought it causes the memory leak but no. I had stopStream function inside getCurrentPosition as else statement but it didn't work either. How can I force app to close stream before it closes this widget? Or am I missing something?
Error looks like this:
E/flutter ( 4655): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: setState() called after dispose(): _GeolocatorActiveState#6b088(lifecycle state: defunct)
E/flutter ( 4655): This error happens if you call setState() on a State object for a widget that no longer appears in the widget tree (e.g., whose parent widget no longer includes the widget in its build). This error can occur when code calls setState() from a timer or an animation callback.
E/flutter ( 4655): The preferred solution is to cancel the timer or stop listening to the animation in the dispose() callback. Another solution is to check the "mounted" property of this object before calling setState() to ensure the object is still in the tree.
E/flutter ( 4655): This error might indicate a memory leak if setState() is being called because another object is retaining a reference to this State object after it has been removed from the tree. To avoid memory leaks, consider breaking the reference to this object during dispose().
So there are two things wrong here:
You call super.dispose outside of dispose method, which is not something you should do.
You nullify _currentComposition stream first and then you try to cancel it, which is too late because you already lost access to that stream. You should switch the order.
By the way, I think you can easily put all stream disposal method inside dispose, rather than close them on button't onTap callback.
Here is your code example that I modified, notice overriden dispose method:
class _GeolocatorActiveState extends State<GeolocatorActive> {
StreamSubscription<Position>? _currentPosition;
double distanceToday = 0.0;
double distanceTotal = 0.0;
bool gpsActive = true;
#override
void initState() {
super.initState();
getCurrentPosition();
}
#override
void dispose() {
_currentPosition?.cancel();
_currentPosition = null;
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
// Some stuff
),
),
backgroundColor: Colors.deepOrange
),
body: Column(
children: [
// some stuff here
TextButton(onPressed: () {
setState(() {
gpsActive = false;
});
Navigator.pushNamed(context, '/');},
child: Text(
'Finish',
)
),
// Some stuff there
],
),
);
}
void getCurrentPosition () {
final positionStream = GeolocatorPlatform.instance.getPositionStream();
if(gpsActive == true){
_currentPosition = positionStream.listen((position) {
setState(() {
long = position.longitude.toString();
lat = position.latitude.toString();
});
});
}
}
}
You can try what it suggests:
Another solution is to check the "mounted" property of this object before calling setState() to ensure the object is still in the tree.
Like this:
if (mounted) {
setState(() {
long = position.longitude.toString();
lat = position.latitude.toString();
});
}

Flutter: Provider shows Exception but app run fine while using default listen:true

I'm Using provider in initState() to call the api but if I use listen:false then it does not update UI and it always shows me loader but if I use listen:true then app works fine but in the terminal it shows me exception and tells me write listen:false.
My UI,
class ChopperNewsCard extends StatefulWidget {
#override
_ChopperNewsCardState createState() => _ChopperNewsCardState();
}
class _ChopperNewsCardState extends State<ChopperNewsCard> {
ScrollController scrollController = ScrollController();
int currentPage = 5;
ChopperApiStore _apiStore = ChopperApiStore();
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
_apiStore = Provider.of<ChopperApiStore>(context,);//<--- here it tells me to write listen:false
});
_apiStore.getResponse(currentPage);
scrollController.addListener(() {
if (scrollController.position.pixels ==
scrollController.position.maxScrollExtent) {
if (currentPage < 20) {
currentPage = currentPage + 5;
_apiStore.getResponse(currentPage);
}
}
});
}
#override
void dispose() {
scrollController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
var height = MediaQuery.of(context).size.height;
var width = MediaQuery.of(context).size.width;
return Observer(builder: (context) {
return Container(
height: height * 0.37,
width: double.infinity,
child: _apiStore.res.articles == null
? CircularProgressIndicator()
: ListView.builder(...),
);
});
}
}
api calling class,
class ChopperApiStore extends _ChopperApiStore with _$ChopperApiStore{}
abstract class _ChopperApiStore with Store{
ApiCall apiCall = ApiCall();
#observable
ChopperNews res = ChopperNews();
#action
Future<void> getResponse(int page) async {
var data = await apiCall.getNews(page);
res = data;
}
}
the error I'm getting,
======== Exception caught by scheduler library =====================================================
The following assertion was thrown during a scheduler callback:
Tried to listen to a value exposed with provider, from outside of the widget tree.
This is likely caused by an event handler (like a button's onPressed) that called
Provider.of without passing `listen: false`.
To fix, write:
Provider.of<ChopperApiStore>(context, listen: false);
It is unsupported because may pointlessly rebuild the widget associated to the
event handler, when the widget tree doesn't care about the value.
The context used was: ChopperNewsCard(dependencies: [MediaQuery], state: _ChopperNewsCardState#8f6cd)
'package:provider/src/provider.dart':
Failed assertion: line 262 pos 7: 'context.owner.debugBuilding ||
listen == false ||
debugIsInInheritedProviderUpdate'
When the exception was thrown, this was the stack:
#2 Provider.of (package:provider/src/provider.dart:262:7)
#3 _ChopperNewsCardState.initState.<anonymous closure> (package:fruitley/week-5/bonus/chopper/widgets/chopper_news_card.dart:32:28)
#4 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1117:15)
#5 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1063:9)
#6 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:971:5)
...
I think if you want to use listen:true to have the build method called you are suppose to override didChangeDependencies rather then initState Checkout this article it might help https://medium.com/swlh/flutter-provider-and-didchangedependencies-15678f502262
ok I'm dumb. I didn't even need to use addPostFrameCallback.
I just removed it and if I want to use provider outside of widget tree that I must use listen:false as it was showing in the exception so now everything makes sense.

Unhandled Exception: setState() called in constructor: ReservationMakingState#861c9(lifecycle state: created, no widget, not mounted)

Im creating an app thats making reservations for boat rentals, but i struggle to fix this problem any1 can help?
Providing code samples:
if (docs.size == 0) {
reservations.doc(resID).set({
'resID': resID,
'name': name,
"surname": surname,
"phoneNumber": phoneNumber,
"rental": ProductCardInCart.rental,
'boat': ProductCardInCart.boat,
'date': date,
'time': time
}).then((value) {
print("Reservation made");
setState(() {
Body.empty = true;
});
}).catchError((error) => print("Failed to reservate: $error"));
} else if (docs.size != 0) {
setState(() {
Body.empty = false;
});
print('jestjus');
}
});
} else {
return;
}
});
}
}
this setstate is working well
.then((value) {
print("Reservation made");
setState(() {
Body.empty = true;
});
but this one isnt and its throwing exception
} else if (docs.size != 0) {
setState(() {
Body.empty = false;
});
print('jestjus');
}
Error that its throwing:
7980): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: setState() called in constructor: ReservationMakingState#861c9(lifecycle state: created, no widget, not mounted)
E/flutter ( 7980): This happens when you call setState() on a State object for a widget that hasn't been inserted into the widget tree yet. It is not necessary to call setState() in the constructor, since the state is already assumed to be dirty when it is initially created.
Thanks for help in advance
The reason that your setState isn't working is because your widget is still being built. It can't update until AFTER the widget has completed its first build.
the reason that this one works
.then((value) {
print("Reservation made");
setState(() {
Body.empty = true;
});
});
is because it is happening after a future .then(() {});
if you would like to have your widget rebuild after it has initially been set up you can useBe careful using this. if you use it within your build method, you will get stuck in a loop! You should have this in a initState method or have some conditional statement before this is run
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
//do something call your set state here
});
}

Exception has occurred. Where is the actual error for this problem in Flutter?

when I run the apps, it still fine when i move to screen B from screen A. after i move to screen C and go back to screen A, this error happen:
Exception has occurred.
FlutterError (setState() called after dispose(): _AdminViewListState#e9f3a(lifecycle state: defunct, not mounted)
This error happens if you call setState() on a State object for a widget that no longer appears in the widget tree (e.g., whose parent widget no longer includes the widget in its build). This error can occur when code calls setState() from a timer or an animation callback.
The preferred solution is to cancel the timer or stop listening to the animation in the dispose() callback. Another solution is to check the "mounted" property of this object before calling setState() to ensure the object is still in the tree.
This error might indicate a memory leak if setState() is being called because another object is retaining a reference to this State object after it has been removed from the tree. To avoid memory leaks, consider breaking the reference to this object during dispose().)
can somebody help me to figure out what is the problem?
The error pointed at this code:
setState(() {
loading = false;
});
and this is the whole coding:
class AdminViewList extends StatefulWidget {
#override
_AdminViewListState createState() => _AdminViewListState();
}
class _AdminViewListState extends State<AdminViewList> {
var loading = false;
final list = new List<AttractionModel>();
final GlobalKey<RefreshIndicatorState> _refresh = GlobalKey<RefreshIndicatorState>();
Future<void> _viewData() async{
list.clear();
setState(() {
loading = true;
});
final response = await http.get(BaseUrl.viewAttraction);
if (response.contentLength == 2) {
} else {
final data = jsonDecode(response.body);
data.forEach((api){
final ab = new AttractionModel(
api['id'],
api['attractionName'],
api['description'],
api['price'],
api['createdData'],
api['idUsers'],
api['name'],
);
list.add(ab);
});
setState(() {
loading = false;
});
}
}
in my debug console :
I/BufferQueueProducer(25860): [SurfaceTexture-0-25860-1](this:0x7b4bcac000,id:1,api:1,p:386,c:-1) disconnect(P): api 1
It's run well after I add this code
if (!mounted) return;
before
setState(() {
loading = false;
});