Error: Could not find the correct Provider <List<Auftrag>> above this Widget

2,950

EDIT Since you are not imediately using the value for the Stream provider in the Home class, you can use a Provider instead as follows;

class  Home extends StatelessWidget {

  final AuthService _auth = AuthService();
  @override
  Widget build(BuildContext context) {
    return Provider(
                  create: (context) => DatabaseServices(), 
                  child: TabContainerIndexedStack()
     );
   },
 }

Then when you need the list, you have to call a provider of the Service class and not the list

final DatabaseService databaseService = Provider.of<DatabaseService>(context);

Then you can access an instance of the list like

databaseService.auftraege

Edit 1

Assuming you have the provider in the home class, don't need to wrap the provider around AuftraegeList() again. This is what you should do.

class _Tab1State extends State<Tab1> with AutomaticKeepAliveClientMixin<Tab1> {


  final DatabaseService databaseService; 

  @override
  void initState() {
    databaseService = Provider.of<DatabaseService>(context);
    super.initState();
    print('initState Tab1');
  }

  @override
  Widget build(BuildContext context) {
    print('build Tab1');
    return Scaffold(
      appBar: AppBar(
        title: Text('Tab1'),
      ),
      body:
        // The use the list directly in this class where needed like `databaseService.auftraege` 
        child: AuftraegeList(),
      )
    );
  }


  @override
  bool get wantKeepAlive => true;
}

Note

  1. In a stateful widget, the BuildContext is available in the initState method and the build method. So you can use BuildContext out of those methods unless you implicitly pass it.
  2. If you need the list in AuftragList() class then get an instance of the list using Provider.of<DatabaseService>(context)
  3. If you need the list to automatically update when a need item is available you can use a StreamSubscription to listen to need stream and add to the list.
  4. When calling the provider of pass the dataType and not the class. That is Provider.of<DatabaseService>(context) and not Provider.of<DatabaseService()>(context).

Edit 2

Since you are getting a stream for you List, use a steamBuilder to builder your Ui

class AuftraegeList extends StatefulWidget {
  @override
  _AuftraegeListState createState() => _AuftraegeListState();
}

class _AuftraegeListState extends State<AuftraegeList> {

  DatabaseService databaseService ;

  @override
  Widget build(BuildContext context) {

    databaseService = Provider.of<DatabaseService>(context);
   // final auftraege = Provider.of<List<Auftrag>>(context);

    return StreamBuilder<List<Auftrag>>( 
        stream: databaseService.auftraege,
        builder: (context, snapshot) {
             if (snapshot.hasData) {
              return  ListView.builder(
                   itemCount: snapshot.data.length, 
                   itemBuilder: (context, index){
                       return AuftragTile(auftrag: snapshot.data[index]);
                  } 
              );
             }else if(snapshot.hasError){
               return Center(child: Text("An error Errored");
             }
             return Center(child: CircularProgessIndicator();
      },

    );
  }
}

Hope this works.

Share:
2,950
Schemee
Author by

Schemee

Updated on December 19, 2022

Comments

  • Schemee
    Schemee over 1 year

    I'm trying to make a buttomtabbar, where there is a List (Stack) on the first Tap page. Somehow there is this error and I just can't figure out why... Screenshot with error warning

    This is my Home file:

    class  Home extends StatelessWidget {
    
      final AuthService _auth = AuthService();
      @override
      Widget build(BuildContext context) {
        return TabContainerIndexedStack();
    }}
    

    This is TabContainerIndexStack():

    class TabContainerIndexedStack extends StatefulWidget {
      TabContainerIndexedStack({Key key}) : super(key: key);
    
      @override
      _TabContainerIndexedStackState createState() =>
          _TabContainerIndexedStackState();
    }
    
    class _TabContainerIndexedStackState extends State<TabContainerIndexedStack> {
      int tabIndex = 0;
      List<Widget> listScreens;
      @override
      void initState() {
        super.initState();
        listScreens = [
          Tab1(),
          Tab2(),
          Tab3(),
        ];
      }
    
    //  @override
    //  bool get wantKeepAlive =>
    //      true; //by default it will be null, change it to true.
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          color: Colors.yellow,
          home: Scaffold(
            body: IndexedStack(index: tabIndex, children: listScreens),
            bottomNavigationBar: BottomNavigationBar(
                currentIndex: tabIndex,
                onTap: (int index) {
                  setState(() {
                    tabIndex = index;
                  });
                },
                items: [
                  BottomNavigationBarItem(
                    icon: Icon(Icons.home),
                    title: Text('Tab1'),
                  ),
                  BottomNavigationBarItem(
                    icon: Icon(Icons.report_problem),
                    title: Text('Tab2'),
                  ),
                  BottomNavigationBarItem(
                    icon: Icon(Icons.settings),
                    title: Text('Tab3'),
                  ),
                ]),
            backgroundColor: Theme.of(context).primaryColor,
          ),
        );
      }
    }
    

    This is my first Tab (other ones work!!!)

    class Tab1 extends StatefulWidget {
      @override
      _Tab1State createState() => _Tab1State();
    }
    
    class _Tab1State extends State<Tab1> with AutomaticKeepAliveClientMixin<Tab1> {
      @override
      void initState() {
        super.initState();
        print('initState Tab1');
      }
    
      @override
      Widget build(BuildContext context) {
        print('build Tab1');
        return Scaffold(
          appBar: AppBar(
            title: Text('Tab1'),
          ),
          body: AuftraegeList()
        );
      }
    
      @override
      bool get wantKeepAlive => true;
    }
    

    I think the problem is right there in the "body: AuftraegeList()..." above..

    Here is the file AuftraegeList():

    class AuftraegeList extends StatefulWidget {
      @override
      _AuftraegeListState createState() => _AuftraegeListState();
    }
    
    class _AuftraegeListState extends State<AuftraegeList> {
      @override
      Widget build(BuildContext context) {
    
        final auftraege = Provider.of<List<Auftrag>>(context);
    
        return ListView.builder(
            itemCount: auftraege.length,
            itemBuilder: (context, index){
          return AuftragTile(auftrag: auftraege[index]);
        },
        );
      }
    }
    

    I hope this is enough to solve my problem. I'm very new to Flutter, so it would be nice, if you can say where EXACTLY I have to change WHAT. Thank you so much!!!

    EDIT: Here is the Code of my home.dart, which is the code, which represents the list in my main view.

    class  Home extends StatelessWidget {
    
      final AuthService _auth = AuthService();
      @override
      Widget build(BuildContext context) {
        return TabContainerIndexedStack();
        /*
        return StreamProvider<List<Auftrag>>.value(
        value: DatabaseService().auftraege,
          child: Scaffold(
            bottomNavigationBar: btmBar(),
         backgroundColor: Colors.blue[50],
          appBar: AppBar(
            title: Text('Home title'),
            backgroundColor: Colors.blue,
            elevation: 0.0,
            actions: <Widget>[
              FlatButton.icon(
                icon: Icon(Icons.person),
                label: Text('logout'),
                onPressed: () async{
                  await _auth.signOut();
                },
              )
            ],
          ),
            body: AuftraegeList(),
            ),
        );
        */
    
      }
    }
    

    (Its the part I commented out)

    Thanks!!

    EDIT (2) !!!

    Latest edit:

    So my first tap class now looks like this (I changed in the Widget build body [] to databaseService.auftraege after declaring databaseService at first).

        class Tab1 extends StatefulWidget {
      @override
      _Tab1State createState() => _Tab1State();
    }
    
    
    class _Tab1State extends State<Tab1> with AutomaticKeepAliveClientMixin<Tab1> {
    
      // Where should I put this line? Whereever I put this, it gives me errors (already imported services/database.dart)
      final DatabaseService databaseService = Provider.of<DatabaseService()>(context);
    
      @override
      void initState() {
        super.initState();
        print('initState Tab1');
      }
    
      @override
      Widget build(BuildContext context) {
        print('build Tab1');
        return Scaffold(
          appBar: AppBar(
            title: Text('Tab1'),
          ),
          body: Provider(
            create: (context) => databaseService.auftraege,
            child: AuftraegeList(),
          )
        );
      }
    
    
      @override
      bool get wantKeepAlive => true;
    }
    

    Maybe its also helpful to show you my services/database

    class DatabaseService{
    
      final String uid;
      DatabaseService({ this.uid });
      // collection reference
       final CollectionReference auftraegeCollection = Firestore.instance.collection('auftraege');
    
      Future updateUserData(String title, String info, int price, String user) async{
        return await auftraegeCollection.document(uid).setData({
          'title' : title,
          'info': info,
          'price': price,
          'user': user,
        });
      }
    
    
      List<Auftrag> _auftragListFromSnapshot(QuerySnapshot snapshot){
        return snapshot.documents.map((doc){
          return Auftrag(
              title: doc.data['title']?? '',
              info: doc.data['info']?? '',
              price: doc.data['price']?? 0,
              user: doc.data['user']?? '',
    
          );
        }).toList();
      }
    
    
      // get auftraege stream
    Stream <List<Auftrag>> get auftraege {
        return auftraegeCollection.snapshots()
        .map(_auftragListFromSnapshot);
    }
    }
    

    When leave the code like that, it gives me an error at this line:

     final DatabaseService databaseService = Provider.of<DatabaseService()>(context);
    

    in my tab1.dart class. It says "Only static members can be accessed in initializers" under "context" and "error: A comparison expression can't be an operand of another comparison expression" as well as "error: The operator '<' isn't defined for the class 'T Function(BuildContext, {listen: bool})'."

    Maybe you know what to do. I think I just put this line at the wrong place.

    ### EDIT (3) ### (Exception)

    ════════ Exception caught by widgets library ═══════════════════════════════════════════════════════ The following assertion was thrown building _BodyBuilder: dependOnInheritedWidgetOfExactType>() or dependOnInheritedElement() was called before _Tab1State.initState() completed.

    When an inherited widget changes, for example if the value of Theme.of() changes, its dependent widgets are rebuilt. If the dependent widget's reference to the inherited widget is in a constructor or an initState() method, then the rebuilt dependent widget will not reflect the changes in the inherited widget.

    Typically references to inherited widgets should occur in widget build() methods. Alternatively, initialization based on inherited widgets can be placed in the didChangeDependencies method, which is called after initState and whenever the dependencies change thereafter.

    The relevant error-causing widget was: Scaffold file:///Users/xxxxxxxxxxxxxxx/AndroidStudioProjects/promi_prototype/lib/screens/home/tab_containter_indexedstack.dart:36:13 When the exception was thrown, this was the stack:

    0 StatefulElement.dependOnInheritedElement. (package:flutter/src/widgets/framework.dart:4467:9)

    1 StatefulElement.dependOnInheritedElement (package:flutter/src/widgets/framework.dart:4510:6)

    2 StatefulElement.inheritFromElement (package:flutter/src/widgets/framework.dart:4458:12)

    3 Element.inheritFromWidgetOfExactType (package:flutter/src/widgets/framework.dart:3556:14)

    4 Provider.of (package:provider/src/provider.dart:259:19)

    It says, the relevant error-causing widget was: tab_containter_indexedstack.dart, I already posted this code at the very beginning of my post. The simulator now only shows the blue background with the tabbar at the bottom. No text at the other tabs (worked before) and no error warning at tab1. Even no headings.

    Greetings!! :)

    .

    .

    .

    ### EDIT (4) ###

    Oh my god xD Sorry for not working.. and THANK YOU for still helping!

    Lets start my the error message:

    The following assertion was thrown building Provider>>(dirty, state: flutter: _DelegateWidgetState#eb784): flutter: Tried to use Provider with a subtype of Listenable/Stream (Stream>). flutter: flutter: This is likely a mistake, as Provider will not automatically update dependents flutter: when Stream> is updated. Instead, consider changing Provider for more specific flutter: implementation that handles the update mechanism, such as: flutter: flutter: - ListenableProvider flutter: - ChangeNotifierProvider flutter: - ValueListenableProvider flutter: - StreamProvider The relevant error-causing widget was: flutter: Provider>> flutter: file:///Users/xxxxxxxxxxxx/AndroidStudioProjects/promi_prototype/lib/screens/my_tabs/tab1.dart:33:13

    So there still is an issue with the Provider in tab1.dart. My guess was to change the Provider thing in AuftragList() because there I was using it the "old" way like Provider.of>(context), just like you mentioned in the edit 18 hours ago.

    This is what I did (Out-commented was before):

    class AuftraegeList extends StatefulWidget {
      @override
      _AuftraegeListState createState() => _AuftraegeListState();
    }
    
    class _AuftraegeListState extends State<AuftraegeList> {
    
      DatabaseService databaseService ;
    
      @override
      Widget build(BuildContext context) {
    
        databaseService = Provider.of<DatabaseService>(context);
       // final auftraege = Provider.of<List<Auftrag>>(context);
    
        return ListView.builder(
           // itemCount: auftraege.length,
           // itemBuilder: (context, index){
              itemCount: databaseService.length, //RED MARK HERE
              itemBuilder: (context, index){
          return AuftragTile(auftrag: databaseService[index]); //RED MARK HERE
        },
        );
      }
    }
    

    I thought this is ok now, but I get red marks under ".lenght" and under "[index]". Compiler sais, that I should create a getter in helpers/database.dart which was what I tried then. But no success. I deleted the getters there then.

    Do you have an idea? Is it right to change the Provider thing in the AuftraegeList() even though the Compiler said issue is in tap1.dart?

    .