简体   繁体   中英

Error: Cloud not find the correct Provider<List<Brew>> above this BrewList Widget

i'm trying to retrieve stepcountvalue on autoupdate basis from firestore. Somehow there is an error and i just can't figure out why...

This is my main.dart

import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_testing/models/brew.dart';
import 'package:flutter_testing/models/user.dart';
import 'package:flutter_testing/screens/Pages/page.dart';
import 'package:flutter_testing/screens/wrapper.dart';
import 'package:flutter_testing/services/auth.dart';
import 'package:flutter_testing/services/database.dart';
import 'dart:async';
import 'package:percent_indicator/circular_percent_indicator.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:pedometer/pedometer.dart';
import 'package:provider/provider.dart';

void main() => runApp(new NewApp());

class NewApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return StreamProvider<User>.value(
      value: AuthService().user,
      child: MaterialApp(
        home: Wrapper(),
      ),
    );
  }
}



class MyApp extends StatefulWidget {

  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {

  final AuthService _auth = AuthService();

  String muestrePasos = "";
  String _km = "Unknown";
  String _calories = "Unknown";
  String stepCountValue = 'Unknown';
  String _showcoin = '0';

  StreamSubscription<int> _subscription;

  double _numerox; //numero pasos
  double _convert;
  double _kmx;
  double burnedx;
  double _coin;
  double _porciento;
  // double percent=0.1;

  @override
  void initState() {
    super.initState();
    //initPlatformState();
    setUpPedometer();
  }

  //inicia codigo pedometer
  void setUpPedometer() {
    Pedometer pedometer = new Pedometer();
    _subscription = pedometer.stepCountStream.listen(_onData,
        onError: _onError, onDone: _onDone, cancelOnError: true);
  }

  void _onData(int stepCountValue1) async {
    // print(stepCountValue); //impresion numero pasos por consola
    setState(() {
      stepCountValue = "$stepCountValue1";
      // print(stepCountValue);
    });

    var dist = stepCountValue1; //pasamos el entero a una variable llamada dist
    double y = (dist + .0); //lo convertimos a double una forma de varias

    setState(() {
      _numerox = y; //lo pasamos a un estado para ser capturado ya convertido a double
    });

    var long3 = (_numerox);
    long3 = num.parse(y.toStringAsFixed(2));
    var long4 = (long3 / 10000);

    int decimals = 1;
    int fac = pow(10, decimals);
    double d = long4;
    d = (d * fac).round() / fac;
    print("d: $d");

    getDistanceRun(_numerox);

    setState(() {
      _convert = d;
      print(_convert);
    });
  }

  void reset() {
    setState(() {
      int stepCountValue1 = 0;
      stepCountValue1 = 0;
      stepCountValue = "$stepCountValue1";
    });
  }

  void _onDone() {}

  void _onError(error) {
    print("Flutter Pedometer Error: $error");
  }

  //function to determine the distance run in kilometers using number of steps
  void getDistanceRun(double _numerox) {
    var distance = ((_numerox * 76) / 100000);
    distance = num.parse(distance.toStringAsFixed(2)); //dos decimales
    var distancekmx = distance * 34;
    distancekmx = num.parse(distancekmx.toStringAsFixed(2));
    //print(distance.runtimeType);
    var coiny = ((_numerox * 125) / 100000);
    coiny = num.parse(coiny.toStringAsFixed(2));

    setState(() {
      _km = "$distance";
      //print(_km);
    });
    setState(() {
      _kmx = num.parse(distancekmx.toStringAsFixed(2));
    });

    setState(() {
      _coin = num.parse(coiny.toStringAsFixed(2));
      //print(_coiny);
    });
  }

  //function to determine the calories burned in kilometers using number of steps
  void getBurnedRun() {
    setState(() {
      var calories = _kmx; //dos decimales
      _calories = "$calories";
      //print(_calories);
    });
  }

  void coins() {
    setState(() {
      var showcoin = _coin;
      _showcoin = "$showcoin";
    });
  }

  //fin codigo pedometer

  @override
  Widget build(BuildContext context) {
    //print(_stepCountValue);
    getBurnedRun();
    coins();
    return StreamProvider<List<Brew>>.value(
        value: DatabaseService().step,
        child: MaterialApp(
          debugShowCheckedModeBanner: false,
          home: new Scaffold(
            appBar: new AppBar(
              title: const Text('Step Counter'),
              backgroundColor: Colors.black54,
              actions: <Widget>[
                FlatButton.icon(
                    icon: Icon(Icons.person),
                    label: Text('logout'),
                    onPressed: () async {
                      await _auth.signOut();
                    }
                ),
          FlatButton.icon(
            icon: Icon(Icons.arrow_back),
            label: Text('New Page'),
            onPressed: () {
              Navigator.of(context)
                  .push(MaterialPageRoute(builder: (context) => pages()));
            }
          ),
          ],
          ),

            body: new ListView(
              padding: EdgeInsets.all(5.0),
              children: <Widget>[
                Container(
                  padding: EdgeInsets.only(top: 10.0),
                  width: 250,
                  //ancho
                  height: 250,
                  //largo tambien por numero height: 300
                  decoration: BoxDecoration(
                      gradient: LinearGradient(
                        begin: Alignment
                            .bottomCenter, //cambia la iluminacion del degradado
                        end: Alignment.topCenter,
                        colors: [Color(0xFFA9F5F2), Color(0xFF01DFD7)],
                      ),
                      borderRadius: BorderRadius.only(
                        bottomLeft: Radius.circular(27.0),
                        bottomRight: Radius.circular(27.0),
                        topLeft: Radius.circular(27.0),
                        topRight: Radius.circular(27.0),
                      )),
                  child: new CircularPercentIndicator(
                    radius: 200.0,
                    lineWidth: 13.0,
                    animation: true,
                    center: Container(
                      child: new Row(
                        crossAxisAlignment: CrossAxisAlignment.center,
                        children: <Widget>[
                          Container(
                            height: 50,
                            width: 50,
                            padding: EdgeInsets.only(left: 20.0),
                            child: Icon(
                              FontAwesomeIcons.walking,
                              size: 30.0,
                              color: Colors.white,
                            ),
                          ),
                          Container(
                            //color: Colors.orange,
                            child: Text(
                              '$stepCountValue',
                              style: TextStyle(
                                  fontWeight: FontWeight.bold,
                                  fontSize: 20.0,
                                  color: Colors.purpleAccent),
                            ),
                            // height: 50.0,
                            // width: 50.0,
                          ),
                        ],
                      ),
                    ),
                    percent: 0.217,
                    //percent: _convert,
                    footer: new Text(
                      "Steps:  $stepCountValue",
                      style: new TextStyle(
                          fontWeight: FontWeight.bold,
                          fontSize: 12.0,
                          color: Colors.purple),
                    ),
                    circularStrokeCap: CircularStrokeCap.round,
                    progressColor: Colors.purpleAccent,
                  ),
                ),
                Divider(
                  height: 5.0,
                ),
                Container(
                  width: 80,
                  height: 100,
                  padding: EdgeInsets.only(left: 25.0, top: 10.0, bottom: 10.0),
                  color: Colors.transparent,
                  child: Row(
                    children: <Widget>[
                      new Container(
                        child: new Card(
                          child: Container(
                            height: 80.0,
                            width: 80.0,
                            decoration: BoxDecoration(
                              image: DecorationImage(
                                image: AssetImage("assets/images/distance.png"),
                                fit: BoxFit.fitWidth,
                                alignment: Alignment.topCenter,
                              ),
                            ),
                            child: Text(
                              "$_km Km",
                              textAlign: TextAlign.right,
                              style: new TextStyle(
                                  fontWeight: FontWeight.bold, fontSize: 14.0),
                            ),
                          ),
                          color: Colors.white54,
                        ),
                      ),
                      VerticalDivider(
                        width: 20.0,
                      ),
                      new Container(
                        child: new Card(
                          child: Container(
                            height: 80.0,
                            width: 80.0,
                            decoration: BoxDecoration(
                              image: DecorationImage(
                                image: AssetImage("assets/images/burned.png"),
                                fit: BoxFit.fitWidth,
                                alignment: Alignment.topCenter,
                              ),
                            ),
                          ),
                          color: Colors.transparent,
                        ),
                      ),
                      VerticalDivider(
                        width: 20.0,
                      ),
                      new Container(
                        child: new Card(
                          child: Container(
                            height: 80.0,
                            width: 80.0,
                            decoration: BoxDecoration(
                              image: DecorationImage(
                                image: AssetImage("assets/images/step.png"),
                                fit: BoxFit.fitWidth,
                                alignment: Alignment.topCenter,
                              ),
                            ),
                          ),
                          color: Colors.transparent,
                        ),
                      ),
                    ],
                  ),
                ),
                Divider(
                  height: 2,
                ),
                Container(
                  padding: EdgeInsets.only(top: 2.0),
                  width: 150,
                  //ancho
                  height: 30,
                  //largo tambien por numero height: 300
                  color: Colors.transparent,
                  child: Row(
                    children: <Widget>[
                      new Container(
                        padding: EdgeInsets.only(left: 40.0),
                        child: new Card(
                          child: Container(
                            child: Text(
                              "$_km Km",
                              textAlign: TextAlign.right,
                              style: new TextStyle(
                                  fontWeight: FontWeight.bold,
                                  fontSize: 14.0,
                                  color: Colors.white),
                            ),
                          ),
                          color: Colors.purple,
                        ),
                      ),
                      VerticalDivider(
                        width: 20.0,
                      ),
                      new Container(
                        padding: EdgeInsets.only(left: 10.0),
                        child: new Card(
                          child: Container(
                            child: Text(
                              "$_calories kCal",
                              textAlign: TextAlign.right,
                              style: new TextStyle(
                                  fontWeight: FontWeight.bold,
                                  fontSize: 14.0,
                                  color: Colors.white),
                            ),
                          ),
                          color: Colors.red,
                        ),
                      ),
                      VerticalDivider(
                        width: 5.0,
                      ),
                      new Container(
                        padding: EdgeInsets.only(left: 10.0),
                        child: new Card(
                          child: Container(
                            child: Text(
                              "$_showcoin Coins",
                              textAlign: TextAlign.right,
                              style: new TextStyle(
                                  fontWeight: FontWeight.bold,
                                  fontSize: 14.0,
                                  color: Colors.white),
                            ),
                          ),
                          color: Colors.black,
                        ),
                      ),
                    ],
                  ),
                ),
              ],
            ),
          ),
        ),
    );
  }
}

this is my wrapper.dart

import 'package:flutter_testing/models/user.dart';
import 'package:flutter_testing/screens/authenticate/authenticate.dart';
import 'package:flutter/material.dart';
import 'package:flutter_testing/main.dart';
import 'package:provider/provider.dart';

class Wrapper extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

    final user = Provider.of<User>(context);

    // return either the Home or Authenticate widget
    if (user == null){
      return Authenticate();
    } else {
      return MyApp();
    }

  }
}

this is page.dart

import 'package:flutter/material.dart';
import 'package:flutter_testing/main.dart';
import 'brew_list.dart';

class pages extends StatefulWidget {
  @override
  _pagesState createState() => _pagesState();
}

class _pagesState extends State<pages> {
  @override
  Widget build(BuildContext context) {

    return Scaffold(
      backgroundColor: Colors.amber,
        appBar: new AppBar(
          actions: <Widget>[
            FlatButton.icon(
              icon: Icon(Icons.arrow_back_ios),
              label: Text('back'), onPressed: () {
                Navigator.of(context)
                    .push(MaterialPageRoute(builder: (context) => MyApp())
                );
            }
            ),
          ],
        ),
      body: BrewList(),
    );
  }
}

this is database.dart

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter_testing/models/brew.dart';

class DatabaseService {

  final String uid;
  DatabaseService({ this.uid });

  // collection reference
  final CollectionReference brewCollection = Firestore.instance.collection('step');
  Future<void> updateUserData(int stepCountValue, int _calories, int _km , int _showcoin) async {
    return await brewCollection.document(uid).setData({
      'stepCountValue': stepCountValue,
      '_calories': _calories,
      '_km': _km,
      '_showcoin': _showcoin,
    });
  }

  // brew list from snapshot
  List<Brew> _brewListFromSnapshot(QuerySnapshot snapshot) {
    return snapshot.documents.map((doc){
      return Brew(
        stepCountValue: doc.data['stepCountValue'] ?? 0,
      );
    }).toList();
  }

  // get brews stream
  Stream<List<Brew>> get step {
    return brewCollection.snapshots()
        .map(_brewListFromSnapshot);
  }

}

this is brew_list.dart

import 'package:flutter_testing/models/brew.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'brew_tile.dart';

class BrewList extends StatefulWidget {
  @override
  _BrewListState createState() => _BrewListState();
}

class _BrewListState extends State<BrewList> {
  @override
  Widget build(BuildContext context) {

    final step = Provider.of<List<Brew>>(context);

    return ListView.builder(
      itemCount: step.length,
      itemBuilder: (context, index) {
        return BrewTile(brew: step[index]);
      },
    );
  }
}

this is brew_tile.dart

import 'package:flutter_testing/models/brew.dart';
import 'package:flutter/material.dart';


 class  BrewTile extends StatelessWidget {

   final Brew brew;
   BrewTile({ this.brew });

   @override
   Widget build(BuildContext context) {
     return Padding(
       padding: const EdgeInsets.only(top: 8.0),
       child: Card(
         margin: EdgeInsets.fromLTRB(20.0, 6.0, 20.0, 0.0),
         child: ListTile(
           leading: CircleAvatar(
             radius: 25.0,
             backgroundColor: Colors.brown[brew.stepCountValue],
           ),
         ),
       ),
     );

   }
 }

this is brew.dart

class Brew {

  final int stepCountValue;

  Brew({ this.stepCountValue });

}

this is pubspec.yaml

name: flutter_testing
description: A new Flutter application.

publish_to: 'none' 

version: 1.0.0+1

environment:
  sdk: ">=2.7.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter


  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^0.1.3
  font_awesome_flutter: ^8.4.0
  decimal: ^0.3.3
  image_picker_saver: ^0.3.0
  pedometer: ^0.0.5
  percent_indicator: ^1.0.14
  flutter_launcher_icons: ^0.7.0
  firebase_auth: ^0.16.0
  cloud_firestore: ^0.13.5
  provider: ^4.2.2+2
  flutter_spinkit: ^4.0.0

dev_dependencies:
  flutter_test:
    sdk: flutter

flutter_icons:
  android: "launcher_icon"
  ios: true
  image_path: "assets/icon/step.png"

flutter:

  # The following line ensures that the Material Icons font is
  # included with your application, so that you can use the icons in
  # the material Icons class.
  uses-material-design: true
  assets:
    - assets/images/

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!!!

This is because there is no Provider<List<Brew>> above BrewList widget.

Typically moving this above MaterialApp should solve the problem. But, in this case, there are just a lot of flaws in your code, not just with respect to flutter but generally.

  • Create a ChangeNotifier

if you are using a provider, you might as well use ChangeNotifier to manage state. Because you are using Brew to wrap only one value, which isn't the best way to use a class. So better move all the logic in main.dart to a ChangeNotifier So what you should instead be doing is,

class BrewNotifier with ChangeNotifier{

  final int stepCountValue;

  Brew({ this.stepCountValue });

List<Brew> _brewlist = [];
get brewList => _brewlist;

//make an API call to populate brewList;


// all other computational logic here.

notifiyListneres();

}

this will not only make your UI sperate from the logic but also make your file more readable and less long.

  • Use provider to create an instance.

You might be using the .value() constructor the wrong way. Use it only if you already have an object instantiated but the better way would be to create it while defining the provider and then accessing it in the tree.

class NewApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
     providers:[
           StreamProvider<User>.value(
           value: AuthService().user,
          ),
          Provider(
          create: DatabaseService(),
         ), 
          ChangeNotifierProvider(
          create: BrewNotifier(),
         ),      
       ]
     ),
     child: MaterialApp(
      home: Wrapper(),
    );
  }
}

  • Access the provider defined using context.

After defining all providers above MaterialApp you can access its values using contex.

for example,

final db = Provider.of<DatabseService>(context, listen= false);

 StreamBuilder<List<Brew>>(
        stream: db.step,                   // Before : DatabaseService().step
        child: Scaffold(                   // no need to define MaterialApp again 
            appBar: AppBar(                // and the `new` keyword is optional in dart

...

...

class _BrewListState extends State<BrewList> {
  @override
  Widget build(BuildContext context) {

    final step = Provider.of<BrewNotifier>(context);

    return ListView.builder(
      itemCount: step.brewList.length,
      itemBuilder: (context, index) {
        return BrewTile(brew: step.brewList[index]);
      },
    );
  }
}

Also, recommend using a proper JSON parser to parse the incoming data.

Please refer this tutorial series on the Provider architecture by Andrea Bizzito if anything I mentioned is confusing.

You should expose the brew list like so:

class NewApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
         StreamProvider<User>.value(value: AuthService().user),
         StreamProvider<List<Brew>>.value(value: DatabaseService().step),
      ],
      child: MaterialApp(
        home: Wrapper(),
      ),
    );
  }
}

before calling:

final step = Provider.of<List<Brew>>(context);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM