如何在main.dart中调用之前已经有一个的changeNotifier?

时间:2020-02-29 08:02:50

标签: flutter google-cloud-firestore flutter-provider flutter-change-notifier

我使用提供程序在一页中显示firestore中的数据,然后又将数据传递到第二页,并在changenotifier中调用了main.dart

但是,每当我尝试导航到第二页时,它将显示此错误:

“ I / flutter(1763):引发了另一个异常:在构建期间调用了setState()或markNeedsBuild()。”

我不做什么。

  • 注意:在main.dart中,我已经有一个changenotifier

首页代码:

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shopping/pages/product_details.dart';
import 'package:shopping/provider/app_provider.dart';
import 'package:shopping/models/product.dart';
class Products extends StatefulWidget {
  @override
ProductsState createState() => ProductsState();
}

class ProductsState extends State<Products> {
  List<Product> products;
  String img;

  @override
  Widget build(BuildContext context) {

    final productProvider = Provider.of<CRUDModel>(context);
   // productProvider.changeProductPage(PAGESTATUS.PRODUCTS);
    return  StreamBuilder<QuerySnapshot>(
            stream: productProvider.fetchProductsAsStream(),
            builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
              if (snapshot.hasData) {
                products = snapshot.data.documents

                    .map((doc) => Product.fromMap(doc.data, doc.documentID))
                    .toList();


     return GridView.builder(
       itemCount: products.length,
       gridDelegate:new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount:2),
     itemBuilder: (BuildContext context,  index){


     return Padding(
    padding:const EdgeInsets.all(4.0),
     child:SingleProd(
         product:products[index]
        // prodPicture: productList[index]['picture'],
         //prodOldPrice: productList[index]['oldPrice'],
         //prodPrice: productList[index]['price'],
       ),
       );
     }
      );
      }
     else {
                return Text('fetching');
              }
  }

  );

  }


}
class SingleProd extends StatelessWidget {
   //final prodName;
  //final prodPicture;
  //final prodOldPrice;
  //final prodPrice;
    final Product product;

  SingleProd({ @required this.product});


  //SingleProd({product.picture});
  @override
  Widget build(BuildContext context) {
 //final appProvider=Provider.of<CRUDModel>(context);

    return Card(
child: Hero(tag: product.id,
 child:
 Material( child: InkWell(
 onTap: (){
  // if(appProvider.selectedPage==PAGESTATUS.PRODUCTDETAILS){
 // appProvider.changeProductPage(PAGESTATUS.PRODUCTDETAILS);
  Navigator.of(context).push(new MaterialPageRoute(builder: (context)=>ProductDetails(
  //here we are passing the value of the products to Product detail page
productDetailName:product.name,
productDetailNewPrice:product.price,
productDetailPicture:product.picture,
//productDetailOldPrice:prodOldPrice,
//productDetailNewPrice:prodPrice,
//productDetailPicture: prodPicture,
)
)
);
//}
},
 child:GridTile(
footer: Container(
  color: Colors.white,
  child: new Row(
    children: <Widget>[
      new Expanded(
        child: new Text(product.name, style: TextStyle(fontWeight: FontWeight.bold, fontSize:16.0),),
      ),
      new Text(
        '\$${product.price} ', style: TextStyle(color: Colors.red, fontWeight: FontWeight.bold),)
    ],
  )
),
 child:Image.network('${product.picture}.jpg', //Image.asset('assets/${product.picture}.jpg',

   fit: BoxFit.cover,),
 ),
 ),
),
),

    );
  }
}   
Future<Widget>_displayImages(){

}

第二页代码:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shopping/provider/app_provider.dart';

//import 'package:shopping/main.dart';
import './home.dart';
class ProductDetails extends StatefulWidget {
  final productDetailName;
  final productDetailNewPrice;
  final productDetailOldPrice;
  final productDetailPicture;

  ProductDetails(
    {
    this.productDetailName,
     this.productDetailNewPrice,
     this.productDetailOldPrice,
     this.productDetailPicture,

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

class _ProductDetailsState extends State<ProductDetails> {
  @override
  Widget build(BuildContext context) {
        ChangeNotifierProvider<CRUDModel>(create: (context) => CRUDModel());

    return Scaffold(
      appBar: new AppBar(
        elevation: 0.1 ,
        backgroundColor: Colors.red,
       title: InkWell(
         onTap: (){Navigator.push(context, MaterialPageRoute(builder:(context)=>new HomePage()));},
         child: Text("MyShop")),
       actions: <Widget>[
                new IconButton(icon: Icon(Icons.search, color: Colors.white,), onPressed:(){},),

       ],
      ),
      body: new ListView(
        children: <Widget>[
          new Container(
            height: 300.0,
            child: GridTile(

              child: Container(
                color: Colors.white,
                child: Image.network(widget.productDetailPicture),
              ),
              footer: Container(
                color: Colors.white70,
                 child: ListTile(
                   leading: Text(widget.productDetailName, style: TextStyle(
                    fontWeight: FontWeight.bold, fontSize: 15.00,
                   ),
                   ),
                   title: new Row(
                     children: <Widget>[
                       Expanded(
                       child:  new Text("\$${widget.productDetailOldPrice}",style: TextStyle(
                       color: Colors.grey, decoration: TextDecoration.lineThrough,
                       ),
                       )
                       ),
                         Expanded(
                       child:  new Text("\$${widget.productDetailNewPrice}",style: TextStyle(
                        fontWeight: FontWeight.bold, color: Colors.red
                       ),
                       )
                       )
                     ],
                   ),
                 ),
              ),
              ),
          ),
              //The First button
           Row(
             children: <Widget>[
               //The Size Button
               Expanded(
                  child: MaterialButton(
                    onPressed: (){
                      showDialog(context:context,
                      builder:(context){
                         return new AlertDialog(
                           title: new Text("Size"),
                           content: new Text("Choose the Size"),
                           actions: <Widget>[
                             new MaterialButton(onPressed: (){
                               Navigator.of(context).pop();
                             },
                             child: new Text("Close"),
                             ),

                           ],
                         );
                      }
                      );
                    },
                    color: Colors.white,
                    textColor: Colors.grey,
                    elevation: 0.2,
                    child: Row(
                      children: <Widget>[
                        Expanded(
                         child: new Text("Size")
                        ),
                         Expanded(
                         child:new Icon(Icons.arrow_drop_down),
                        ),

                      ],
                    ),
                  ),
               ),


            Expanded(
                  child: MaterialButton(
                    onPressed: (){
                      showDialog(context:context,
                      builder:(context){
                         return new AlertDialog(
                           title: new Text("Colors"),
                           content: new Text("Choose a Color"),
                           actions: <Widget>[
                             new MaterialButton(onPressed: (){
                               Navigator.of(context).pop();
                             },
                             child: new Text("Close"),
                             ),

                           ],
                         );
                      }
                      );
                    },
                    color: Colors.white,
                    textColor: Colors.grey,
                    elevation: 0.2,
                    child: Row(
                      children: <Widget>[
                        Expanded(
                         child: new Text("Color")
                        ),
                         Expanded(
                         child:new Icon(Icons.arrow_drop_down),
                        ),

                      ],
                    ),
                  ),
               ),

               Expanded(
                  child: MaterialButton(
                     onPressed: (){
                      showDialog(context:context,
                      builder:(context){
                         return new AlertDialog(
                           title: new Text("Quantity"),
                           content: new Text("Choose the Quantity"),
                           actions: <Widget>[
                             new MaterialButton(onPressed: (){
                               Navigator.of(context).pop();
                             },
                             child: new Text("Close"),
                             ),

                           ],
                         );
                      }
                      );
                    },
                    color: Colors.white,
                    textColor: Colors.grey,
                    elevation: 0.2,
                    child: Row(
                      children: <Widget>[
                        Expanded(
                         child: new Text("QTY")
                        ),
                         Expanded(
                         child:new Icon(Icons.arrow_drop_down),
                        ),

                      ],
                    ),
                  ),
               ),
             ],
              ),


                 //The Second button
           Row(
             children: <Widget>[
               //The Size Button
               Expanded(
                  child: MaterialButton(
                    onPressed: (){},
                    color: Colors.red,
                    textColor: Colors.white,
                    elevation: 0.2,
                   child: new Text("Buy Now"),
                  ),
               ),
               new IconButton(icon: Icon(Icons.add_shopping_cart, color: Colors.red,), onPressed: null,),
               new IconButton(icon: Icon(Icons.favorite_border, color: Colors. red,), onPressed: null,),

             ],
              ),
              new Divider(),
              new ListTile(
                title: Text("Product Description", style: TextStyle(fontWeight: FontWeight.bold),),
                subtitle: new Text("Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets",),
              ),
              new Divider(),
              new Row(
                children: <Widget>[
                  new  Padding(padding: const EdgeInsets.fromLTRB(12.0, 5.0, 5.0, 5.0),
                  child: new Text("Product Name", style: TextStyle(color: Colors.grey),),),
                  new Padding(padding: EdgeInsets.all(5.0),
                  child: new Text(widget.productDetailName),)
                ],
              ),
              new Row(
                children: <Widget>[
                  //remember to create product brand
                  new  Padding(padding: const EdgeInsets.fromLTRB(12.0, 5.0, 5.0, 5.0),
                  child: new Text("Product Brand", style: TextStyle(color: Colors.grey),),),
                   new Padding(padding: EdgeInsets.all(5.0),
                  child: new Text("Brand X"),),
                ],
              ),
              new Row(
                children: <Widget>[
                  //Add the product condition
                  new  Padding(padding: const EdgeInsets.fromLTRB(12.0, 5.0, 5.0, 5.0),
                  child: new Text("Product Condition", style: TextStyle(color: Colors.grey),),),
                   new Padding(padding: EdgeInsets.all(5.0),
                  child: new Text("New"),)
                ],
              ),
              new Divider(),
              Padding(padding: const EdgeInsets.all(8.0),
             child: new Text("Similar Products"),),
              //Similar Products
              new Container(
                height: 360.0,
                child: SimilarProducts(),
              )
        ],
      ),
    );
  }
}
class SimilarProducts extends StatefulWidget {
  @override
  _SimilarProductsState createState() => _SimilarProductsState();
}

class _SimilarProductsState extends State<SimilarProducts> {
 var productList=[

    {
      "name":"Black Dress",
      "picture":"images/products/dress2.jpeg",
      "oldPrice":150,
      "price":   80,
    },
    {
      "name":" M Pant1",
      "picture":"images/products/pants1.jpg",
      "oldPrice":120,
      "price":   50,
    },
    {
      "name":"Hill",
      "picture":"images/products/hills1.jpeg",
      "oldPrice":130,
      "price":   80,
    },
      {
      "name":"W Skirt",
      "picture":"images/products/skt1.jpeg",
      "oldPrice":150,
      "price":   100,
    },

  ];
  @override
  Widget build(BuildContext context) {
     return GridView.builder(
       itemCount: productList.length,
       gridDelegate:new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount:2),
     itemBuilder: (BuildContext context, int index){

     return  SimilarSingleProd(
         prodName: productList[index]['name'],
         prodPicture: productList[index]['picture'],
         prodOldPrice: productList[index]['oldPrice'],
         prodPrice: productList[index]['price'],
       );
     }
      );
  }
}



class SimilarSingleProd extends StatelessWidget {
  final prodName;
  final prodPicture;
  final prodOldPrice;
  final prodPrice;

 SimilarSingleProd({this.prodName, this.prodPicture,this.prodOldPrice,this.prodPrice});
  @override
  Widget build(BuildContext context) {
    return Card(
child: Hero(tag: new Text("hero 1"),
 child:
 Material( child: InkWell(
onTap: ()=>Navigator.of(context).push(new MaterialPageRoute(builder: (context)=>ProductDetails(
  //here we are passing the value of the products to Product detail page
productDetailName:prodName,
productDetailOldPrice:prodOldPrice,
productDetailNewPrice:prodPrice,
productDetailPicture: prodPicture,
)
)
),
 child:GridTile(
footer: Container(
  color: Colors.white,
  child: new Row(
    children: <Widget>[
      new Expanded(
        child: new Text(prodName, style: TextStyle(fontWeight: FontWeight.bold, fontSize:16.0),),
      ),
      new Text("\$$prodPrice", style: TextStyle(color: Colors.red, fontWeight: FontWeight.bold),)
    ],
  )
),
 child: Image.asset(prodPicture, 
   fit: BoxFit.cover,),
 ),
 ),
),
),
    );
  }




}

main.dart代码:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shopping/pages/home.dart';
import 'package:shopping/pages/splash.dart';
import 'package:shopping/provider/app_provider.dart';
import 'provider/user_provider.dart';
import './pages/login.dart';
//import 'package:path_provider/path_provider.dart';

/*void main() {

  runApp(
    new MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
  primaryColor: Colors.blue.shade900
),
home: Login(),
    )
  );
}*/
void main() {

    WidgetsFlutterBinding.ensureInitialized(); 

   runApp(MultiProvider(providers: [

     ChangeNotifierProvider.value(value: UserProvider.initialize()),
    //second notifier that is given me problem
       ChangeNotifierProvider.value(value: CRUDModel()),



     ],

   child:new MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
  primaryColor: Colors.blue.shade900
),
home:ScreenController(),
    ),
     ),
    );
}

class ScreenController extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final user=Provider.of<UserProvider>(context);
    switch(user.status){
      case Status.Uninitialized:
      return Splash();
      case Status.UnAuthenticated:
      case Status.Authenticating:
      return Login();
      case Status.Authenticated:
      return HomePage();
      default:
      return Login();
    }
  }
}

提供商本身

import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:shopping/db/Api.dart';
import 'package:shopping/models/product.dart';

enum PAGESTATUS { INITIAL, PRODUCTS, PRODUCTDETAILS, PRODUCTFETCHFAIL }

class CRUDModel extends ChangeNotifier {

    PAGESTATUS _pageStatus = PAGESTATUS.INITIAL;

    PAGESTATUS get pageStatus => _pageStatus;


  //Api _api = locator<Api>();
  String path = "Products";
  Api _api = Api();

  List<Product> products;

  Future<List<Product>> fetchProducts() async {
    try {


      //notifyListeners();
      var result = await _api.getDataCollection();
      products = result.documents
          .map((doc) => Product.fromMap(doc.data, doc.documentID))
          .toList();
    } catch (e) {
      notifyListeners();
      print(e.toString());
    }
    return products;
  }


  Stream<QuerySnapshot> fetchProductsAsStream() {
    notifyListeners();
    return _api.streamDataCollection();
  }



}

1 个答案:

答案 0 :(得分:0)

您的fetchProductsAsStream方法在被调用后立即调用notifyListeners(),这可能是导致问题的原因。在创建build时会从StreamBuilder函数中调用此方法,但是notifyListeners将触发附加的build,因此会出现错误。您应该可以简单地从notifyListeners中删除fetchProductsAsStream,因为无论如何都不会有任何更改要通知。