8
votes

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,
      ),
    );
  }
2
Could you include the entire stacktrace? It is unclear on which line your exception was trown - Rémi Rousselet
Edited with stacktrace @RémiRousselet - Victor Roberti Camolesi
Ah yes, you passed the flag to one of the Provider.of call, but there's a second one and it doesn't have the flag. Both needs it - Rémi Rousselet
I did that before but it's not working either @RémiRousselet Actually, I'm having problems with provider in many parts of the code, flutter just doesn't let me update a model with a provider using notifyListeners. I only got away with some providers because I used listen: false but that's the same as not using notifyListeners at all. It keeps giving the message from the title of this thread. - Victor Roberti Camolesi

2 Answers

3
votes

The error seems to point out to these two lines of code to be causing the issue.

#3 _OrderHistoryState._onAfterBuild package:shinier_store/screens/order_history.dart:60

#4 _OrderHistoryState.build. package:shinier_store/screens/order_history.dart:67

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 that var model = Provider.of<OrderModel>(context); inside Widget 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.

0
votes

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.