保存地址时出现问题 - 错误"setState() or markNeedsBuild() called during build." 如何解决此错误?



我有一个Flutter项目。我收到这个警告,";在生成过程中调用了setState()或markNeedsBuild()"这对我来说是个大问题。我该如何解决这个问题?

这是警告。

=====基础库捕获异常=============================================在调度的通知时引发以下断言LocationProvider:setState()或markNeedsBuild()在生成期间调用。

此_继承提供者范围<LocationProvider>小部件不能标记为需要构建,因为框架已经在构建小部件的过程。小部件可以标记为需要仅当其祖先之一当前建筑物由于框架生成,因此允许出现此异常父窗口小部件位于子窗口小部件之前,这意味着脏的子窗口将永远建造。否则,框架可能不会访问此小部件在这个构建阶段。setState()或调用的markNeedsBuild()为:_继承的ProviderScope<LocationProvider>value:正在侦听value的"LocationProvider"实例当前为当发出有问题的调用时生成的是:Builder当引发了异常,这是堆栈:#0 Element.markNeedsBuild.(包:flutter/src/widgets/framework.dart:4424:11)#1 Element.markNeedsBuild(包:flutter/src/widgets/framework.dart:4439:6)#2 _InitheritedProviderScopeElement.markNeedsNotifyDependents(包:provider/src/herited_provider.dart:570:5)#3个ChangeNotifier.notifyListeners(包:flutter/src/foundation/change_notifier.dart:308:24)#4 LocationProvider.setAddAddressData(包:flatter_grocery/provider/location_provider.dart:350:5)#5 _添加新地址屏幕状态_initLoading(包:flatter_grocery/view/screens/address/add_new_address_screen.dart:48:61)#6 _AddNewAddressScreenState.initState(软件包:flatter_grocery/view/screens/address/add_new_address_screen.dart:88:5)#7 StatefulElement_firstBuild(包:flutter/src/widgets/framework。dart:4893:57)#8 ComponentElement.mount(包:flutter/src/widgets/framework.dart:4729:5)…正常元件安装(151个框架)#159 Element.inflateWidget(包:flutter/src/widgets/framework.dart:3790:14)#160 MultiChildRenderObjectElement.inflateWidget(包:flutter/src/widgets/framework.dart:6422:36)#161 Element.updateChild(包:flutter/src/widgets/framework.dart:3540:18)#162 RenderObjectElement.updateChildren(包:flutter/src/widgets/framework。dart:5845:32)#163 MultiChildRenderObjectElement.update(包:flutter/src/widgets/framework.dart:6445:17)#164 Element.updateChild(包:flutter/src/widgets/framework.dart:3501:15)#165 ComponentElement.performRebuild(包:flutter/src/widgets/framework.dart:4780:16)#166 StatefulElement.performRebuild(包:flutter/src/widgets/framework.dart:4928:11)#167 Element.rebuild(包:flutter/src/widgets/framework。dart:4477:5)#168 StatefulElement.update(包:flutter/src/widgets/framework.dart:4960:5)#169 Element.updateChild(包:flutter/src/widgets/framework.dart:3501:15)#170 ComponentElement.performRebuild(包:flutter/src/widgets/framework.dart:4780:16)#171 Element.rebuild(包:flutter/src/widgets/framework.dart:4477:5)#172 ProxyElement.update(包:flutter/src/widgets/framework.dart:5108:5)#173 Element.updateChild(包:flutter/src/widgets/framework.dart:3501:15)#174 ComponentElement.performRebuild(包:flutter/src/widgets/framework.dart:4780:16)#175 Element.rebuild(包:flutter/src/widgets/framework。dart:4477:5)#176 ProxyElement.update(包:flutter/src/widgets/framework.dart:5108:5)#177 _继承通知元素更新(包:flutter/src/widgets/herited_notifier.dart:111:11)#178 Element.updateChild(包:flutter/src/widgets/framework.dart:3501:15)#179 SingleChildRenderObjectElement.update(包:flutter/src/widgets/framework.dart:6291:14)#180 Element.updateChild(包:flutter/src/widgets/framework.dart:3501:15)#181 ComponentElement.performRebuild(包:flutter/src/widgets/framework.dart:4780:16)#182 StatefulElement.performRebuild(包:flutter/src/widgets/framework.dart:4928:11)#183 Element.rebuild(包:flutter/src/widgets/framework.dart:4477:5)#184 StatefulElement.update(包:flutter/src/widgets/framework.dart:4960:5)#185 Element.updateChild(包:flutter/src/widgets/framework.dart:3501:15)#186 SingleChildRenderObjectElement.update(包:flutter/src/widgets/framework.dart:6291:14)#187 Element.updateChild(包:flutter/src/widgets/framework.dart:3501:15)#188 SingleChildRenderObjectElement.update(包:flutter/src/widgets/framework.dart:6291:14)#189 Element.updateChild(包:flutter/src/widgets/framework.dart:3501:15)#190 ComponentElement.performRebuild(包:flutter/src/widgets/framework.dart:4780:16)#191 Element.rebuild(包:flutter/src/widgets/framework。dart:4477:5)#192 ProxyElement.update(包:flutter/src/widgets/framework.dart:5108:5)#193 Element.updateChild(包:flutter/src/widgets/framework.dart:3501:15)#206 _飞镖(飞镖:ui/钩。飞镖:151:10)#207 PlatformDispatcher_drawFrame(省道:ui/platform_dispatcher.省道:308:5)#208 _drawFrame(dart:ui/hooks.dart:115:31)(从dart:async中删除了3个帧)LocationProvider发送通知为:的实例"LocationProvider">

这是我的代码

import ...
class LocationProvider with ChangeNotifier {
final SharedPreferences sharedPreferences;
final LocationRepo locationRepo;
LocationProvider({@required this.sharedPreferences, this.locationRepo});
Position _position = Position(longitude: 0, latitude: 0, timestamp: DateTime.now(), accuracy: 1, altitude: 1, heading: 1, speed: 1, speedAccuracy: 1);
Position _pickPosition = Position(longitude: 0, latitude: 0, timestamp: DateTime.now(), accuracy: 1, altitude: 1, heading: 1, speed: 1, speedAccuracy: 1);
bool _loading = false;
bool get loading => _loading;
TextEditingController _locationController = TextEditingController();
TextEditingController get locationController => _locationController;
Position get position => _position;
Position get pickPosition => _pickPosition;
Placemark _address = Placemark();
Placemark _pickAddress = Placemark();
String _currentAddressText = '';
String get currentAddressText => _currentAddressText;
Placemark get address => _address;
Placemark get pickAddress => _pickAddress;
List<Marker> _markers = <Marker>[];
List<Marker> get markers => _markers;
bool _buttonDisabled = true;
bool _changeAddress = true;
GoogleMapController _mapController;
List<Prediction> _predictionList = [];
bool _updateAddAddressData = true;
bool get buttonDisabled => _buttonDisabled;
GoogleMapController get mapController => _mapController;
// for get current location
void getCurrentLocation(BuildContext context, bool fromAddress, {GoogleMapController mapController}) async {
_loading = true;
notifyListeners();
Position _myPosition;
try {
Position newLocalData = await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
_myPosition = newLocalData;
}catch(e) {
_myPosition = Position(
latitude: double.parse('0'),
longitude: double.parse('0'),
timestamp: DateTime.now(), accuracy: 1, altitude: 1, heading: 1, speed: 1, speedAccuracy: 1,
);
}
if(fromAddress) {
_position = _myPosition;
}else {
_pickPosition = _myPosition;
}
if (mapController != null) {
mapController.animateCamera(CameraUpdate.newCameraPosition(
CameraPosition(target: LatLng(_myPosition.latitude, _myPosition.longitude), zoom: 17),
));
}
Placemark _myPlaceMark;
try {
if(!ResponsiveHelper.isWeb()) {
List<Placemark> placeMarks = await placemarkFromCoordinates(_myPosition.latitude, _myPosition.longitude);
_myPlaceMark = placeMarks.first;
}else {
String _address = await getAddressFromGeocode(LatLng(_myPosition.latitude, _myPosition.longitude), context);
_myPlaceMark = Placemark(name: _address, locality: '', postalCode: '', country: '');
}
}catch (e) {
String _address = await getAddressFromGeocode(LatLng(_myPosition.latitude, _myPosition.longitude), context);
_myPlaceMark = Placemark(name: _address, locality: '', postalCode: '', country: '');
}
fromAddress ? _address = _myPlaceMark : _pickAddress = _myPlaceMark;
if(fromAddress) {
_locationController.text = placeMarkToAddress(_address);
}
_loading = false;
notifyListeners();
}
void updatePosition(CameraPosition position, bool fromAddress, String address, BuildContext context, bool forceNotify) async {
if(_updateAddAddressData || forceNotify) {
_loading = true;
notifyListeners();
try {
if (fromAddress) {
_position = Position(
latitude: position.target.latitude, longitude: position.target.longitude, timestamp: DateTime.now(),
heading: 1, accuracy: 1, altitude: 1, speedAccuracy: 1, speed: 1,
);
} else {
_pickPosition = Position(
latitude: position.target.latitude, longitude: position.target.longitude, timestamp: DateTime.now(),
heading: 1, accuracy: 1, altitude: 1, speedAccuracy: 1, speed: 1,
);
}
if (_changeAddress) {
if (!ResponsiveHelper.isWeb()) {
List<Placemark> placeMarks = await placemarkFromCoordinates(position.target.latitude, position.target.longitude);
fromAddress ? _address = placeMarks.first : _pickAddress = placeMarks.first;
} else {
String _addresss = await getAddressFromGeocode(LatLng(position.target.latitude, position.target.longitude), context);
fromAddress ? _address = Placemark(name: _addresss) : _pickAddress = Placemark(name: _addresss);
}
if(address != null) {
_locationController.text = address;
}else if(fromAddress) {
_locationController.text = placeMarkToAddress(_address);
}
} else {
_changeAddress = true;
}
} catch (e) {}
_loading = false;
notifyListeners();
}else {
_updateAddAddressData = true;
}
}
// End Address Position
void draggableAddress() async {
try {
_loading = true;
notifyListeners();
if(ResponsiveHelper.isMobilePhone()) {
List<Placemark> placemarks = await placemarkFromCoordinates(_position.latitude, _position.longitude);
_address = placemarks.first;
_locationController.text = placeMarkToAddress(_address);
}
_loading = false;
notifyListeners();
}catch(e) {
_loading = false;
notifyListeners();
}
}
// delete user address
void deleteUserAddressByID(int id, int index, Function callback) async {
ApiResponse apiResponse = await locationRepo.removeAddressByID(id);
if (apiResponse.response != null && apiResponse.response.statusCode == 200) {
_addressList.removeAt(index);
callback(true, 'Deleted address successfully');
notifyListeners();
} else {
String errorMessage;
if (apiResponse.error is String) {
print(apiResponse.error.toString());
errorMessage = apiResponse.error.toString();
} else {
ErrorResponse errorResponse = apiResponse.error;
print(errorResponse.errors[0].message);
errorMessage = errorResponse.errors[0].message;
}
callback(false, errorMessage);
}
}
bool _isAvaibleLocation = false;
bool get isAvaibleLocation => _isAvaibleLocation;
// user address
List<AddressModel> _addressList;
List<AddressModel> get addressList => _addressList;
Future<ResponseModel> initAddressList(BuildContext context) async {
ResponseModel _responseModel;
ApiResponse apiResponse = await locationRepo.getAllAddress();
if (apiResponse.response != null && apiResponse.response.statusCode == 200) {
_addressList = [];
apiResponse.response.data.forEach((address) => _addressList.add(AddressModel.fromJson(address)));
_responseModel = ResponseModel(true, 'successful');
} else {
ApiChecker.checkApi(context, apiResponse);
}
notifyListeners();
return _responseModel;
}
bool _isLoading = false;
bool get isLoading => _isLoading;
String _errorMessage = '';
String get errorMessage => _errorMessage;
String _addressStatusMessage = '';
String get addressStatusMessage => _addressStatusMessage;
updateAddressStatusMessage({String message}){
_addressStatusMessage = message;
}
updateErrorMessage({String message}){
_errorMessage = message;
}
Future<ResponseModel> addAddress(AddressModel addressModel, BuildContext context) async {
_isLoading = true;
notifyListeners();
_errorMessage = '';
_addressStatusMessage = null;
ApiResponse apiResponse = await locationRepo.addAddress(addressModel);
_isLoading = false;
ResponseModel responseModel;
if (apiResponse.response != null && apiResponse.response.statusCode == 200) {
Map map = apiResponse.response.data;
initAddressList(context);
String message = map["message"];
responseModel = ResponseModel(true, message);
_addressStatusMessage = message;
} else {
String errorMessage = apiResponse.error.toString();
if (apiResponse.error is String) {
print(apiResponse.error.toString());
errorMessage = apiResponse.error.toString();
} else {
ErrorResponse errorResponse = apiResponse.error;
print(errorResponse.errors[0].message);
errorMessage = errorResponse.errors[0].message;
}
responseModel = ResponseModel(false, errorMessage);
_errorMessage = errorMessage;
}
notifyListeners();
return responseModel;
}
// for address update screen
Future<ResponseModel> updateAddress(BuildContext context, {AddressModel addressModel, int addressId}) async {
_isLoading = true;
notifyListeners();
_errorMessage = '';
_addressStatusMessage = null;
ApiResponse apiResponse = await locationRepo.updateAddress(addressModel, addressId);
_isLoading = false;
ResponseModel responseModel;
if (apiResponse.response != null && apiResponse.response.statusCode == 200) {
Map map = apiResponse.response.data;
initAddressList(context);
String message = map["message"];
responseModel = ResponseModel(true, message);
_addressStatusMessage = message;
} else {
String errorMessage = apiResponse.error.toString();
if (apiResponse.error is String) {
print(apiResponse.error.toString());
errorMessage = apiResponse.error.toString();
} else {
ErrorResponse errorResponse = apiResponse.error;
print(errorResponse.errors[0].message);
errorMessage = errorResponse.errors[0].message;
}
responseModel = ResponseModel(false, errorMessage);
_errorMessage = errorMessage;
}
notifyListeners();
return responseModel;
}
// for save user address Section
Future<void> saveUserAddress({Placemark address}) async {
String userAddress = jsonEncode(address);
try {
await sharedPreferences.setString(AppConstants.USER_ADDRESS, userAddress);
} catch (e) {
throw e;
}
}
String getUserAddress() {
return sharedPreferences.getString(AppConstants.USER_ADDRESS) ?? "";
}
// for Label Us
List<String> _getAllAddressType = [];
List<String> get getAllAddressType => _getAllAddressType;
int _selectAddressIndex = 0;
int get selectAddressIndex => _selectAddressIndex;
updateAddressIndex(int index, bool notify) {
_selectAddressIndex = index;
if(notify) {
notifyListeners();
}
}
initializeAllAddressType({BuildContext context}) {
if (_getAllAddressType.length == 0) {
_getAllAddressType = [];
_getAllAddressType = locationRepo.getAllAddressType(context: context);
}
}
void setLocation(String placeID, String address, GoogleMapController mapController) async {
_loading = true;
notifyListeners();
PlacesDetailsResponse detail;
ApiResponse response = await locationRepo.getPlaceDetails(placeID);
detail = PlacesDetailsResponse.fromJson(response.response.data);
_pickPosition = Position(
longitude: detail.result.geometry.location.lat, latitude: detail.result.geometry.location.lng,
timestamp: DateTime.now(), accuracy: 1, altitude: 1, heading: 1, speed: 1, speedAccuracy: 1,
);
_pickAddress = Placemark(name: address);
_changeAddress = false;
if(mapController != null) {
mapController.animateCamera(CameraUpdate.newCameraPosition(CameraPosition(target: LatLng(
detail.result.geometry.location.lat, detail.result.geometry.location.lng,
), zoom: 17)));
}
_loading = false;
notifyListeners();
}
void disableButton() {
_buttonDisabled = true;
notifyListeners();
}
void setAddAddressData() {
_position = _pickPosition;
_address = _pickAddress;
_locationController.text = placeMarkToAddress(_address);
_updateAddAddressData = false;
notifyListeners();
}
void initialAddressData(BuildContext context) {
_position = Position(longitude: double.parse(Provider.of<SplashProvider>(context, listen: false).configModel.ecommerceLocationCoverage.longitude ?? '0'),
latitude: double.parse(Provider.of<SplashProvider>(context, listen: false).configModel.ecommerceLocationCoverage.latitude ?? '0'),timestamp: DateTime.now(),
heading: 1, accuracy: 1, altitude: 1, speedAccuracy: 1, speed: 1);
_address = _pickAddress;
_locationController.text = placeMarkToAddress(_address);
_updateAddAddressData = false;
notifyListeners();
}
void setPickData() {
_pickPosition = _position;
_pickAddress = _address;
_locationController.text = placeMarkToAddress(_address);
}
void setMapController(GoogleMapController mapController) {
_mapController = mapController;
}
Future<String> getAddressFromGeocode(LatLng latLng, BuildContext context) async {
ApiResponse response = await locationRepo.getAddressFromGeocode(latLng);
String _address = 'Unknown Location Found';
if(response.response.statusCode == 200 && response.response.data['status'] == 'OK') {
_address = response.response.data['results'][0]['formatted_address'].toString();
}else {
ApiChecker.checkApi(context, response);
}
return _address;
}
Future<List<Prediction>> searchLocation(BuildContext context, String text) async {
if(text != null && text.isNotEmpty) {
ApiResponse response = await locationRepo.searchLocation(text);
if (response.response.statusCode == 200 && response.response.data['status'] == 'OK') {
_predictionList = [];
response.response.data['predictions'].forEach((prediction) => _predictionList.add(Prediction.fromJson(prediction)));
} else {
ApiChecker.checkApi(context, response);
}
}
return _predictionList;
}
String placeMarkToAddress(Placemark placeMark) {
return '${placeMark.name ?? ''}'
' ${placeMark.subAdministrativeArea ?? ''}'
' ${placeMark.isoCountryCode ?? ''}';
}
}

我的UI`我的UI代码

class AddressScreen extends StatefulWidget {
final AddressModel addressModel;
AddressScreen({this.addressModel});
@override
State<AddressScreen> createState() => _AddressScreenState();
}
class _AddressScreenState extends State<AddressScreen> {
bool _isLoggedIn;
@override
void initState() {
// TODO: implement initState
super.initState();
_isLoggedIn = Provider.of<AuthProvider>(context, listen: false).isLoggedIn();
if(_isLoggedIn) {
Provider.of<LocationProvider>(context, listen: false).initAddressList(context);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: ResponsiveHelper.isMobilePhone()? null: ResponsiveHelper.isDesktop(context)? PreferredSize(child: WebAppBar(), preferredSize: Size.fromHeight(120)) : AppBarBase(),
body: _isLoggedIn ? Consumer<LocationProvider>(
builder: (context, locationProvider, child) {
return RefreshIndicator(
onRefresh: () async {
await Provider.of<LocationProvider>(context, listen: false).initAddressList(context);
},
backgroundColor: Theme.of(context).primaryColor,
child: SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(minHeight: ResponsiveHelper.isDesktop(context) ? MediaQuery.of(context).size.height - 560 : MediaQuery.of(context).size.height),
child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [
Center(
child: Container(
width: 1170,
padding: EdgeInsets.all(Dimensions.PADDING_SIZE_SMALL),
margin: EdgeInsets.only(top: ResponsiveHelper.isDesktop(context) ? 20 : 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
getTranslated('saved_address', context),
style: poppinsRegular.copyWith(color: ColorResources.getTextColor(context)),
),
InkWell(
// onTap:() =>  Navigator.pushNamed(context, RouteHelper.getAddAddressRoute('address', 'add', AddressModel())),
onTap:() {Provider.of<LocationProvider>(context, listen: false).updateAddressStatusMessage(message: '');
Navigator.of(context).pushNamed(RouteHelper.getAddAddressRoute('address', 'add', AddressModel()), arguments: AddNewAddressScreen());
},
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 10,vertical: 5),
decoration: BoxDecoration(
color: ResponsiveHelper.isDesktop(context)? Theme.of(context).primaryColor : Colors.transparent,
borderRadius: BorderRadius.circular(5),
),
child: Row(
children: [
Icon(Icons.add, color: ResponsiveHelper.isDesktop(context)? Colors.white : ColorResources.getTextColor(context)),
Text(
getTranslated('add_new', context),
style: poppinsRegular.copyWith(color: ResponsiveHelper.isDesktop(context)? Colors.white : ColorResources.getTextColor(context)),
),
],
),
),
),
],
),
),
),
locationProvider.addressList != null ? locationProvider.addressList.length > 0 ?
Scrollbar(
child: Column(
children: [
Center(
child: SizedBox(
width: 1170,
child: ResponsiveHelper.isDesktop(context)
?  GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisSpacing: ResponsiveHelper.isDesktop(context) ? 13 : 5,
mainAxisSpacing: ResponsiveHelper.isDesktop(context) ? 13 : 5,
childAspectRatio:ResponsiveHelper.isDesktop(context) ? 4.5 : ResponsiveHelper.isTab(context) ? 4 : 3.5,
crossAxisCount: ResponsiveHelper.isDesktop(context) ? 2 : ResponsiveHelper.isTab(context) ? 2 : 1),
itemCount: locationProvider.addressList.length,
padding: EdgeInsets.symmetric(horizontal: Dimensions.PADDING_SIZE_DEFAULT,vertical: Dimensions.PADDING_SIZE_DEFAULT),
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return AddressWidget(
addressModel: locationProvider.addressList[index],
index: index,
);
},
)
: ListView.builder(
padding: EdgeInsets.all(Dimensions.PADDING_SIZE_SMALL),
itemCount: locationProvider.addressList.length,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) => AddressWidget(
addressModel: locationProvider.addressList[index],
index: index,
),
),
),
),
locationProvider.addressList.length <= 4 ?  const SizedBox(height: 300) : SizedBox(),
ResponsiveHelper.isDesktop(context) ? FooterView() : SizedBox(),
],
),
)
: NoDataScreen()
: Center(child: CircularProgressIndicator(valueColor: AlwaysStoppedAnimation<Color>(Theme.of(context).primaryColor))),
],
),
),
),
);
},
) : NotLoggedInScreen(),
);
}
}

`

您在initState中调用future(initAddressList),它调用notifyListeners,从而导致重建。由于initState不是异步的,这意味着未来很可能会在框架已经在构建小部件的过程中完成。这就是错误消息的内容。

尽管您可以使用addPostFramCallBack解决此问题,但更好的解决方案是使用FutureBuilder将此逻辑从initState移动到build方法中,请参阅此处。这样,小部件的构建只会在您的未来完成后开始,并且您可以在等待未来完成时显示进度指示器。

相关内容

最新更新