6

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?

Code Ratchet
  • 5,758
  • 18
  • 77
  • 141

1 Answers1

17

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

pr0gramist
  • 8,305
  • 2
  • 36
  • 48
  • I'm at the early stages learning flutter, so any docs or recommendations from other developers whom have vastly more experience than me I'll be sure to listen too. The above worked, much appreciated, i'll be sure to check the docs and follow the example outined. – Code Ratchet Dec 04 '19 at 09:59
  • Thanx brother, I spent many hours figuring out this. Finally, I got your answer. – Shahzad Akram Dec 30 '19 at 14:18
  • What I was failing to understand is that routing is part of MaterialApp. Therefore, I thought it was ok to define some providers after the material app. However, this contradicts with the recommendation to "keep the state above the widgets that use it." since MaterialApp is one of the first widgets, or am I missing something here? – cksrc Sep 17 '22 at 09:48