Javid A.
Javid A.

Reputation: 291

Unhandled Exception: A Products was used after being disposed

I'm using MultiProvider and I get this error:

Unhandled Exception: A Products was used after being disposed. Once you have called dispose() on a Products, it can no longer be used.

Here is my main.dart file. What is wrong with this structure?

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider.value(
          value: Auth(),
        ),
        ChangeNotifierProxyProvider<Auth, Products>(
          update: (ctx, auth, previousProducts) => Products(
            auth.token,
            auth.userId,
            previousProducts == null ? [] : previousProducts.items,
          ),
        ),
        ChangeNotifierProvider.value(
          value: Cart(),
        ),
        ChangeNotifierProxyProvider<Auth, Orders>(
          update: (ctx, auth, previousOrders) => Orders(
            auth.token,
            auth.userId,
            previousOrders == null ? [] : previousOrders.orders,
          ),
        ),
      ],
      child: Consumer<Auth>(
        builder: (ctx, auth, _) => MaterialApp(
          title: 'MyShop',
          theme: ThemeData(
            primarySwatch: Colors.purple,
            accentColor: Colors.deepOrange,
            fontFamily: 'Lato',
          ),
          home: auth.isAuth
              ? ProductOverviewScreen()
              : FutureBuilder(
            future: auth.tryAutoLogin(),
            builder: (ctx, authResultSnapshot) =>
            authResultSnapshot.connectionState ==
                ConnectionState.waiting
                ? SplashScreen()
                : AuthScreen(),
          ),
          routes: {
            ProductDetailScreen.routeName: (ctx) => ProductDetailScreen(),
            CartScreen.routeName: (ctx) => CartScreen(),
            OrdersScreen.routeName: (ctx) => OrdersScreen(),
            UserProductsScreen.routeName: (ctx) => UserProductsScreen(),
            EditProductsScreen.routeName: (ctx) => EditProductsScreen(),
          },
        ),
      ),
    );
  }
}

Upvotes: 11

Views: 9813

Answers (7)

Tasnuva Tavasum oshin
Tasnuva Tavasum oshin

Reputation: 4750

use yourProvider.value Instead of Create

  itemBuilder: (ctx, index) => ChangeNotifierProvider.value(
        value: products[index],
        child: ProductItem(),
      ),
      itemCount: products.length,
    );

Upvotes: 23

SwiftiSwift
SwiftiSwift

Reputation: 8757

Do it like this for example:

        return MaterialPageRoute(
          builder: (_) => ChangeNotifierProvider<EntryPermitViewModel>.value(
            value: EntryPermitViewModel(),
            child: const EntryPermitScreen(),
          ),
        );

Upvotes: 2

commandiron
commandiron

Reputation: 1473

add delay for Products provider in ProductsOverviewScreen;

@override
void initState() {
  Future.delayed(Duration(seconds: 1)).then((_) {
    Provider.of<Products>(context, listen: false).fetchAndSetProducts();
  });
  super.initState();
}

Upvotes: 1

Ba khadher
Ba khadher

Reputation: 21

This is how you can fix it

GridView.builder(
          padding: const EdgeInsets.all(10),
          gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
              crossAxisCount: 2,
              childAspectRatio: 3 / 2,
              crossAxisSpacing: 10,
              mainAxisSpacing: 10),
          itemBuilder: ((context, i) => ChangeNotifierProvider.value( //   <--
               
                value: productsItems[i],
                child: ProductItem(),
              )),
          itemCount: productsItems.length,
        );
      }

Upvotes: 2

Abhi
Abhi

Reputation: 101

I was also getting the same error and I resolved it by:

ChangeNotifierProvider<"Provider name">.value(value:<PassedValue>);

It seems ChangeNotifierProvider creates an instance of the provider and when its work is done dispose() method is called and therefore, that instance is cleared with ChangeNotifierProvider.value, that's not the case and we are able to re-use the earlier created instance.

Here are the official docs: https://pub.dev/packages/provider

Upvotes: 2

Mr. AJ Pangare
Mr. AJ Pangare

Reputation: 1

Use

Navigator.of(context).pushNamed('/');

In your drawer where you called logout. This will fix that Thank you..

Upvotes: -1

Eng.Yaserco
Eng.Yaserco

Reputation: 11

I think you have to add Products Provider to providers: [] above proxy providers as the definition of Auth Provider like the following:

providers: [
    ChangeNotifierProvider<Auth>.value(
                          value: Auth(),
     ChangeNotifierProvider<Products>.value(
                          value: Products(),
    ChangeNotifierProxyProvider<Auth, Products>(
      update: (ctx, auth, previousProducts) => Products(
        auth.token,
        auth.userId,
        previousProducts == null ? [] : previousProducts.items,
      ),
    ),
    ChangeNotifierProvider<Cart>.value(
      value: Cart(),
    ),
    ChangeNotifierProxyProvider<Auth, Orders>(
      update: (ctx, auth, previousOrders) => Orders(
        auth.token,
        auth.userId,
        previousOrders == null ? [] : previousOrders.orders,
      ),
    ),
  ],

Upvotes: 0

Related Questions