Search code examples
flutterproviderstate-management

Flutter provider loosing value when navigating to another screen


I'm new to Flutter and provider package so any assistance would be great, so the issue I have my main.dart file which is as follows:

 void main() => runApp(
      MaterialApp(
        debugShowCheckedModeBanner: false,
        theme: ThemeData.light(),
        home: ChangeNotifierProvider(
          create: (_) => InterestingMomentProvider(),
          child: Home(),
        ),
     ),
  );

This builds my Home widget, I won't post it all as It's extremely large, however, what happens is I click a button and it passes in a string to the provider class an adds it to the list which is outlined as follows:

import 'package:flutter/widgets.dart';

class InterestingMomentProvider extends ChangeNotifier {

  List<String> _moments = [];

  List<String> get moments => _moments;

  void addMoment(String time){
    _moments.add(time);
  }

  int momentsTotal(){
    return _moments.length;
  }

}

Adding a breakpoint on the addMoment method I can confirm _moments has all the strings.

I then press a button which navigates to another screen, the navigation code is as follows:

Navigator.push(context, MaterialPageRoute(builder: (context) => MomentsRecorded()),);

MomentsRecorded widget is as follows:

class MomentsRecorded extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Moments'),
        centerTitle: true,        
      ),
      body: Center(
        child: MomentsList()
        ),
    );
  }
}

the first error was:

Could not find the correct Provider<InterestingMomentProvider> above this Consumer<InterestingMomentProvider> Widget

To fix, please:

  * Ensure the Provider<InterestingMomentProvider> is an ancestor to this Consumer<InterestingMomentProvider> Widget
  * Provide types to Provider<InterestingMomentProvider>
  * Provide types to Consumer<InterestingMomentProvider>
  * Provide types to Provider.of<InterestingMomentProvider>()
  * Always use package imports. Ex: `import 'package:my_app/my_code.dart';
  * Ensure the correct `context` is being used.

I then tweaked the body to look like the following and the error dissappeared:

 body: Center(
        child: ChangeNotifierProvider(
          create: (_) => InterestingMomentProvider(),
          child: MomentsList())
        ),

However inside MomentLists widget, I try to loop through the list of moments from the provider class, however when debugging _moments is 0 ?

MomentsList widget:

class MomentsList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Consumer<InterestingMomentProvider>(
      builder: (context, momentData, child){
        return momentData.momentsTotal() > 0 ? ListView.builder(
          itemCount: momentData.momentsTotal(),
          itemBuilder: (BuildContext context, int index) {
            final moment = momentData.moments[index];
            return ListTile(
                title: Text(moment),
            );
          }
        ) : Center(child: Text('no moments recorded'),);
      }

    );
  }
}

Can someone please explain why this maybe?


Solution

  • This is happening, because your provider is defined in home property of MaterialApp, so when you change the route the provider will be removed too.

    Solution: move the provider above the MaterialApp like this:

     void main() => runApp(
      ChangeNotifierProvider(
        create: (_) => InterestingMomentProvider(),
        child: MaterialApp(
          debugShowCheckedModeBanner: false,
          theme: ThemeData.light(),
          home: Home()
        ),
      ),
    );
    

    If you are afraid that this isn't right - checkout the docs, they are doing the same