So, I have a project in flutter and I’m trying to build a list of Cards where the contents depends on my OrderModel class and I’m trying to use Provider to achieve this, but I get this error:
════════ Exception caught by scheduler library ══════════════════════════
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(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.
‘package:provider/src/provider.dart’:
Failed assertion: line 193 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:193
#3 _OrderHistoryState._onAfterBuild
package:shinier_store/screens/order_history.dart:60
#4 _OrderHistoryState.build.
package:shinier_store/screens/order_history.dart:67
#5 SchedulerBinding._invokeFrameCallback
package:flutter/…/scheduler/binding.dart:1102
#6 SchedulerBinding.handleDrawFrame
package:flutter/…/scheduler/binding.dart:1049
…
═════════════════════════════════════════════════════════
Stacktrace for the Provider call at _onAfterBuild()
I/flutter ( 3092): #0 _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:42:39)
I/flutter ( 3092): #1 _AssertionError._throwNew (dart:core-patch/errors_patch.dart:38:5)
I/flutter ( 3092): #2 Provider.of package:provider/src/provider.dart:193
I/flutter ( 3092): #3 _OrderHistoryState._onAfterBuild package:shinier_store/screens/order_history.dart:61
I/flutter ( 3092): #4 _OrderHistoryState.build.<anonymous closure>
package:shinier_store/screens/order_history.dart:71
I/flutter ( 3092): #5 SchedulerBinding._invokeFrameCallback
package:flutter/…/scheduler/binding.dart:1102
I/flutter ( 3092): #6 SchedulerBinding.handleDrawFrame
package:flutter/…/scheduler/binding.dart:1049
I/flutter ( 3092): #7 SchedulerBinding._handleDrawFrame
package:flutter/…/scheduler/binding.dart:957
I/flutter ( 3092): #8 _rootRun (dart:async/zone.dart:1126:13)
I/flutter ( 3092): #9 _CustomZone.run (dart:async/zone.dart:1023:19)
I/flutter ( 3092): #10 _CustomZone.runGuarded (dart:async/zone.dart:925:7)
I/flutter ( 3092): #11 _invoke (dart:ui/hooks.dart:259:10)
I/flutter ( 3092): #12 _drawFrame (dart:ui/hooks.dart:217:3)
I don’t know how can I possibly solve it since I added the listen:false to my Provider call. I tried using WidgetBinding, cause I thought the Provider call should be made after build is done but that didn’t seem to solve the problem.
Here are the codes:
OrderModel class
class OrderModel extends ChangeNotifier {
List<Order> myOrders;
bool isLoading = true;
String errMsg;
int page = 1;
bool endPage = false;
void getMyOrder({UserModel userModel}) async {
try {
isLoading = true;
notifyListeners();
myOrders = await WooCommerce().getMyOrders(userModel: userModel, page: 1);
page = 1;
errMsg = null;
isLoading = false;
endPage = false;
notifyListeners();
} catch (err) {
errMsg =
"There is an issue with the app during request the data, please contact admin for fixing the issues " +
err.toString();
isLoading = false;
notifyListeners();
}
}
void loadMore({UserModel userModel}) async {
try {
isLoading = true;
page = page + 1;
notifyListeners();
var orders =
await WooCommerce().getMyOrders(userModel: userModel, page: page);
myOrders = [...myOrders, ...orders];
if (orders.length == 0) endPage = true;
errMsg = null;
isLoading = false;
notifyListeners();
} catch (err) {
errMsg =
"There is an issue with the app during request the data, please contact admin for fixing the issues " +
err.toString();
isLoading = false;
notifyListeners();
}
}
}
order_history.dart – state class
class _OrderHistoryState extends State<OrderHistory> {
void _onAfterBuild(BuildContext context){
Provider.of<OrderModel>(context, listen: false)
.getMyOrder(userModel: Provider.of<UserModel>(context));
}
@override
Widget build(BuildContext context) {
var formatter = DateFormat('dd-MM-yyyy');
var model = Provider.of<OrderModel>(context);
WidgetsBinding.instance.addPostFrameCallback((_) => _onAfterBuild(context));
return Scaffold(
appBar: AppBar(
title: Text(
'Order History',
style: TextStyle(fontWeight: FontWeight.bold),
),
elevation: 0.0),
body: model.myOrders == null ? Center() :
Padding(
padding: const EdgeInsets.all(10.0),
child: ListView.separated(
separatorBuilder: (_, __) => SizedBox(height: 10.0),
itemCount: model.myOrders.length,
itemBuilder: (context, index) {
String stat = model.myOrders[index].status;
return Card(
color: _buildColor(stat),
elevation: 3.5,
...
}
}
main.dart – build method
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => UserModel()),
ChangeNotifierProvider(create: (_) => CartModel()),
ChangeNotifierProvider(create: (_) => SearchModel()),
ChangeNotifierProvider(create: (_) => OrderModel()),
],
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primaryColor: Colors.white,
backgroundColor: Colors.white,
canvasColor: Colors.white,
),
home: MainTabs(),
debugShowCheckedModeBanner: false,
localizationsDelegates: [
i18n,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: i18n.supportedLocales,
),
);
}
5
Answers
The error seems to point out to these two lines of code to be causing the issue.
The repro you’ve provided is incomplete and I can only guess the required flag
listen: false
has been added on_onAfterBuild()
. However, the error logs points thatvar model = Provider.of<OrderModel>(context);
insideWidget build()
needs to also have the flag. The reason for this flag requirement is explained in the docs.If you’re still having issues, a working minimal repro will be helpful for us to understand why this behavior occurs.
I also found out that use of BlocProvider, even without the listen parameter seems to solve this. But in this case you would be using BLOC for your state management.
In all cases that I use var yyystate = BlocProvider.of(context); I always add the listen parameter.
I too got similar error and found out that in the newer version of Provider Package (I am using
provider: ^6.0.1
) you have to passlisten: false
whereever you are updating the provider data.For example on a Tap of button or any Widgets onChanged Event. Below is an example with TextField onChanged callback.
If you use provider version ^6.0.2,
use:
Instead of this:
If you are using provider
^6.0.2
then use:not: