我有一个如下的屏幕页面。我不断在控制台上收到以下错误。
Exception caught by foundation library ═══════════════════════════════════════════════
setState() or markNeedsBuild() called during build.
如果我在以下文件中注释掉Provider.of<AppData>(context, listen: false).setAllStoreData(allStoreData);
,该错误将消失。
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../share/style.dart';
import '../share/backend.dart';
import '../share/app_data.dart';
class ChooseStorePage extends StatefulWidget {
ChooseStorePage({Key key, this.title}) : super(key: key);
final String title;
@override
_ChooseStorePageState createState() => _ChooseStorePageState();
}
class _ChooseStorePageState extends State<ChooseStorePage> {
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: ChooseStoreInnerWidget(),
),
);
}
}
class ChooseStoreInnerWidget extends StatefulWidget {
ChooseStoreInnerWidget({Key key}) : super(key: key);
@override
_ChooseStoreInnerWidgetState createState() => _ChooseStoreInnerWidgetState();
}
class _ChooseStoreInnerWidgetState extends State<ChooseStoreInnerWidget> {
Future _allStoreDataFuture = getFile('stores.json');
Widget build(BuildContext context) {
return FutureBuilder<dynamic>(
future: _allStoreDataFuture,
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
List<Widget> children;
if (snapshot.hasData) {
var allStoreData = snapshot.data;
Provider.of<AppData>(context, listen: false).setAllStoreData(allStoreData);
print(snapshot.data.toString());
children = [
Text('Choose Store',
textAlign: TextAlign.left,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: largeTextSize,
color: blackColor,
))
];
} else {
children = <Widget>[
Container(
padding: EdgeInsets.fromLTRB(0, 20, 0, 0),
child: Center(
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircularProgressIndicator(),
Text(" Loading"),
],
),
),
),
];
}
return ListView(
children: children,
);
},
);
}
}
此外,我的提供者数据类如下:
import 'package:uuid/uuid.dart';
import 'package:flutter/material.dart';
class AppData extends ChangeNotifier {
String uid;
String phoneNumber;
String selectedStoreId;
String selectedStoreLabel;
dynamic cart;
dynamic storeData;
dynamic allStoreData;
AppData() {
resetCart();
}
void resetCart() {
cart = {
"uid": uid,
"phoneNumber": phoneNumber,
"lines": [],
"coupon": null,
"discount": [],
"tips_percent": 0,
"tips": 0.00,
"totals": {'subtotal': 0.00,
'tax': 0.00,
'total': 0.00,
'total_qty': 0,},
"dinning_option": null,
"arrival_time": null,
"special_request": null,
};
notifyListeners();
}
void setUID(val) {
uid = val;
notifyListeners();
}
void setPhoneNumber(val) {
phoneNumber = val;
notifyListeners();
}
void setSelectedStoreId(val) {
selectedStoreId = val;
notifyListeners();
}
void setSelectedStoreLabel(val) {
selectedStoreLabel = val;
notifyListeners();
}
void setStoreData(val) {
storeData = val;
notifyListeners();
}
void setAllStoreData(val) {
allStoreData = val;
notifyListeners();
}
String generateOrderId() {
String storeId = storeData['store_id'];
var ms = (new DateTime.now()).millisecondsSinceEpoch;
String epoch = (ms / 1000).round().toString();
String phonePostfix = phoneNumber.substring(phoneNumber.length - 5);
String orderId = "$storeId-$epoch-$phonePostfix";
cart['order_id'] = orderId;
// notifyListeners();
return orderId;
}
void prepareCheckout() {
double epoch =
((new DateTime.now()).millisecondsSinceEpoch / 1000).round().toDouble();
DateTime today = new DateTime.now();
String dateTimeSlug =
"${today.year.toString()}-${today.month.toString().padLeft(2, '0')}-${today.day.toString().padLeft(2, '0')} ${today.hour.toString().padLeft(2, '0')}:${today.minute.toString().padLeft(2, '0')}:${today.second.toString().padLeft(2, '0')}";
cart['phone_number'] = phoneNumber;
cart['uid'] = uid;
cart['negative_epoch'] = epoch * -1;
cart['date_slug'] = dateTimeSlug;
// notifyListeners();
}
void addCartItem(val) {
dynamic line = new Map.from(val);
cart['lines'].add(line);
_recalculateCart();
}
void removeCartItem(index) {
cart['lines'].removeAt(index);
_recalculateCart();
}
void addCartTip(val) {
cart['tips_percent'] = val['rate'];
_recalculateCart();
}
void updateQty(index, qty) {
cart['lines'][index]['_user']['_qty'] = qty;
_recalculateCart();
}
void addCartCoupon(val) {
val = val.toUpperCase();
cart['coupon'] = val;
_recalculateCart();
}
List<dynamic> __processCoupon() {
String couponCode = cart['coupon'];
dynamic couponData;
if (storeData['coupon'].containsKey(couponCode)) {
couponData = storeData['coupon'][couponCode];
} else {
return null;
}
// check valid date
DateTime untilDate = DateTime.parse(couponData['until']);
DateTime today = DateTime.now();
if (today.compareTo(untilDate) == 1) {
return null;
}
// check criteria
String criteriaUnit = couponData['criteria_unit'];
double criteriaMetric = couponData['criteria_metric'];
List<dynamic> criteriaItems = couponData['criteria_items'];
double userMetric = 0;
List<dynamic> discountableLines = [];
if (criteriaUnit == 'item') {
for (dynamic line in cart['lines']) {
if ((criteriaItems != null && criteriaItems.contains(line['course'])) ||
(criteriaItems == null)) {
userMetric = userMetric + line['_user']['_qty'];
discountableLines.add(new Map.from(line));
}
}
} else if (criteriaUnit == 'dollar') {
for (dynamic line in cart['lines']) {
if ((criteriaItems != null && criteriaItems.contains(line['course'])) ||
(criteriaItems == null)) {
userMetric = userMetric + line['_user']['_qty'] * line['price'];
discountableLines.add(new Map.from(line));
}
}
}
if (!(userMetric >= criteriaMetric)) {
return null;
}
// redeem
String discountUnit = couponData['discount_unit'];
double discountMetric = couponData['discount_metric'];
List<dynamic> results = [];
if (discountUnit == 'item') {
// choose the lowest course from item
int discountMulti = 1;
if (couponData['discount_multi'] == true) {
discountMulti = userMetric ~/ criteriaMetric;
discountMulti = (discountMetric * discountMulti).toInt();
}
List<dynamic> flatDiscountableLines =
__flatDiscountableLines(discountableLines);
for (int i = 1; i <= discountMulti; i++) {
dynamic discountLine = flatDiscountableLines[i];
dynamic finalLine = new Map.from(discountLine);
finalLine['price'] = finalLine['price'] * -1;
results.add(finalLine);
}
} else if (discountUnit == 'dollar') {
dynamic finalLine = {'item': 'Discount', 'course': discountMetric * -1};
results.add(finalLine);
} else if (discountUnit == 'percent') {
dynamic finalLine = {
'item': 'Discount',
'course': discountMetric * userMetric * -1
};
results.add(finalLine);
}
return results;
}
List<dynamic> __flatDiscountableLines(discountableLines) {
List<dynamic> flatList = [];
for (var line in discountableLines) {
for (int i = 0; i <= line['_user']['_qty']; i++) {
dynamic flat = {'course': line['course'], 'price': line['price']};
flatList.add(flat);
}
}
flatList.sort((a, b) {
if (a['price'] > b['price']) {
return 1;
}
return -1;
});
return flatList;
}
void _recalculateCart() {
// coupon
if (cart['coupon'] != null) {
cart['discount'] = __processCoupon();
}
if (cart['discount'] == null){
cart['discount'] = [];
}
//line total
double subTotal = 0.00;
int totalQty = 0;
for (dynamic item in cart['lines']) {
int _qty = item['_user']['_qty'];
double _price = item['price'];
double _lineTotal = _price * _qty;
item['_user']['_line_total'] = _lineTotal;
subTotal = subTotal + _lineTotal;
totalQty = totalQty + _qty;
}
//tax
double taxRate = storeData['tax']['rate'];
double tax = taxRate * subTotal;
tax = double.parse(tax.toStringAsFixed(2));
//subtotal
for (dynamic row in cart['discount']) {
subTotal = subTotal + row['price'];
}
subTotal = double.parse(subTotal.toStringAsFixed(2));
//tips
double tips = cart['tips_percent'] * subTotal;
tips = double.parse(tips.toStringAsFixed(2));
//total
double total = subTotal + tax + cart['tips'];
total = double.parse(total.toStringAsFixed(2));
cart['tips'] = tips;
cart['totals'] = {
'subtotal': subTotal,
'tax': tax,
'total': total,
'total_qty': totalQty,
};
notifyListeners();
}
}