the error is thrown in two areas (and the app freezes (when the app is minimized, when phones back button is clicked, or when another app runs on top of the flutter app. Flutter version: 1.20.2 (previous versions did not have this issue): The two functions are:
@override
void initState() {
super.initState();
getItems();
}
getItems() async {
initClearVisibility();
initFilters();
setState(() {
loadingItems = true;
Visibility(visible: true, child: CircularProgressIndicator());
});
QuerySnapshot querySnapshot = await query.get();
items = querySnapshot.docs;
lastDocument = querySnapshot.docs[querySnapshot.docs.length - 1];
setState(() {
loadingItems = false;
Visibility(visible: false, child: CircularProgressIndicator());
});
}
initClearVisibility() {
if (Str.filterSelectCategory != Str.CATEGORY) {
clearCategoryVisible = true;
allCategoriesVisible = false;
categoryValue = Str.filterSelectCategory;
setState(() {});
}
}
initFilters() async {
filterDefaultItems();
}
filterDefaultItems() async {
query = _firestore
.collection(Str.ITEMS)
.where(Str.IS_ITEM_SOLD, isEqualTo: false)
.where(Str.ADDRESS, isEqualTo: userAddress1)
//.orderBy(Str.DATE_POSTED)
.limit(perPage);
}
Second area is on the following code where I am also getting: :
class FABBottomAppBarItem {
FABBottomAppBarItem({this.iconData, this.itemColor}); //, this.text});
IconData iconData;
var itemColor;
//String text;
}
class FABBottomAppBar extends StatefulWidget {
FABBottomAppBar({
this.items,
this.centerItemText,
this.height: 65.0,
this.iconSize: 24.0,
this.backgroundColor,
this.color,
this.selectedColor,
this.notchedShape,
this.onTabSelected,
}) {
assert(this.items.length == 2 || this.items.length == 4);
}
final List<FABBottomAppBarItem> items;
final String centerItemText;
final double height;
final double iconSize;
final Color backgroundColor;
final Color color;
final Color selectedColor;
final NotchedShape notchedShape;
final ValueChanged<int> onTabSelected;
@override
State<StatefulWidget> createState() => FABBottomAppBarState();
}
class FABBottomAppBarState extends State<FABBottomAppBar> {
//int _selectedIndex = 0;
int unreadCount = 0;
_updateIndex(int index) {
widget.onTabSelected(index);
setState(() {
//_selectedIndex = index;
});
}
@override
void initState() {
super.initState();
countDocuments();
}
@override
Widget build(BuildContext context) {
List<Widget> items = List.generate(widget.items.length, (int index) {
return _buildTabItem(
item: widget.items[index],
index: index,
onPressed: _updateIndex,
);
});
items.insert(items.length >> 1, _buildMiddleTabItem());
return BottomAppBar(
shape: widget.notchedShape,
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: items,
),
color: widget.backgroundColor,
);
}
Widget _buildMiddleTabItem() {
return Expanded(
child: SizedBox(
height: MediaQuery.of(context).size.height * 0.075, //widget.height,
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SizedBox(
height: MediaQuery.of(context).size.height * 0.04,
),
Text(
widget.centerItemText ?? '',
style: TextStyle(
color: BwerereTheme.bwerereRed,
fontSize: 14.0,
fontWeight: FontWeight.w900),
),
],
),
),
);
}
Widget _buildTabItem({
FABBottomAppBarItem item,
int index,
ValueChanged<int> onPressed,
})
{
return Expanded(
child: SizedBox(
height: MediaQuery.of(context).size.height * 0.065,
child: Material(
type: MaterialType.transparency,
child: InkWell(
onTap: () => onPressed(index),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Stack(
children: <Widget>[
Icon(item.iconData,
color: item.itemColor,
size: IconTheme.of(context).size * 1.2),
index == 2 ? badge() : Container()
],
)
],
),
),
),
),
);
}
Widget badge() => unreadCount < 1
? Container()
: Container(
padding: EdgeInsets.all(4.0),
decoration: BoxDecoration(
color: BwerereTheme.bwerereRed, shape: BoxShape.circle),
child: Center(
child: RobotoFont(
text: "$unreadCount",
textSize: 12.0,
textColor: Colors.white,
fontWeight: FontWeight.w400),
));
void countDocuments() async {
final uid = await FetchUserData().getCurrentUserID();
QuerySnapshot _myDoc = await FirebaseFirestore.instance
.collection("userUnreadMessages")
.doc(uid)
.collection(Str.MESSAGE_COLLECTION)
.get();
List<DocumentSnapshot> _myDocCount = _myDoc.docs;
setState(() {
unreadCount = _myDocCount.length;
print('NOTIY LENGTH::: $unreadCount');
});
}
}
THE ERROR FROM FRAMEWORK.DART for FABBottomAppBarState.
The same error thrown on the getItems on HomePage()
Exception has occurred. FlutterError (setState() called after dispose(): FABBottomAppBarState#250ac(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().)
Further investigation then shows that the app takes about 400MB of memory (Ram) for the phone which I find rather too high.
Help on figuring out the issue will really help. Thanks in advance.
Additional information: Error occurs when running on android 7.0, flutter 1.20.2. See similar/related issue on https://github.com/flutter/flutter/issues/35900. Note that I upgraded to Flutter 1.20.2 adnd Downgrading to 1.7.5 will require a lot of changes I made after upgrading especially on Firestore (NOTE: https://firebase.flutter.dev/docs/migration which was recently updated).
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.
Yes, it's a…
setState method Null safety Notify the framework that the internal state of this object has changed. Whenever you change the internal state of a State object, make the change in a function that you pass to setState: setState(() { _myState = newValue; }); The provided callback is immediately called synchronously.
Mounting is the process of creating the state of a StatefulWidget and attaching it to a BuildContext.
After an await
, your widget may not be mounted anymore. Doing setState gives you an exception at that time. This is actually a good thing, the code that follows should not be executing anyway, since you are somewhere else.
You have three options about the "setState() called after dispose()" exception:
if (!mounted) return;
between each await
and setState()
. It may be a good habit to put it after each await
. This also stops the async function and hides the exception, if you are allergic to it.setState()
calls with setStateIfMounted()
and define it as:void setStateIfMounted(f) {
if (mounted) setState(f);
}
However, if (mounted) setState()
does not stop the async function, so this 3rd option is the worst between the three as discussed here.
I also explain these approaches in this video.
You can use:
if (this.mounted) { // check whether the state object is in tree
setState(() {
// make changes here
});
}
The mounted
checks whether Whether this State
object is currently in a tree
.
mounted class
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With