错误:在构建期间调用了 setState() 或 markNeedsBuild()
Posted
技术标签:
【中文标题】错误:在构建期间调用了 setState() 或 markNeedsBuild()【英文标题】:Error: setState() or markNeedsBuild() called during build 【发布时间】:2021-11-14 16:57:03 【问题描述】:我目前正在构建一个天气应用程序,它可以为我们提供温度和气候信息(如果下雨、刮风或晴天)。我正在使用 http 和地理定位器包来构建我的应用程序。使用 api 密钥和 json解码我正在检索信息。
我收到以下错误
在 ws://127.0.0.1:57160/pspjoes2GlI=/ws 上侦听的调试服务
Error: setState() or markNeedsBuild() called during build.
This Overlay widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
The widget on which setState() or markNeedsBuild() was called was:
Overlay-[LabeledGlobalKey<OverlayState>#044ff]
The widget which was currently being built when the offending call was made was:
Builder
at Object.throw_ [as throw] (http://localhost:64547/dart_sdk.js:5348:11)
at http://localhost:64547/packages/flutter/src/widgets/widget_span.dart.lib.js:29299:23
at framework.StatefulElement.new.markNeedsBuild (http://localhost:64547/packages/flutter/src/widgets/widget_span.dart.lib.js:29307:26)
at overlay$.OverlayState.new.setState (http://localhost:64547/packages/flutter/src/widgets/widget_span.dart.lib.js:17689:43)
at overlay$.OverlayState.new.rearrange (http://localhost:64547/packages/flutter/src/widgets/widget_span.dart.lib.js:31894:12)
这是我的代码
Main.dart
import 'package:flutter/material.dart';
import 'package:clima/screens/loading_screen.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget
@override
Widget build(BuildContext context)
return MaterialApp(
theme: ThemeData.dark(),
home: LoadingScreen(),
);
LoadingScreen.dart
import 'package:flutter/material.dart';
import 'location_screen.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'dart:convert';
import'package:clima/services/weather.dart';
const APIkey = '9f2e463e61258ef5a8b9a9bd11733b62c';
class LoadingScreen extends StatefulWidget
@override
_LoadingScreenState createState() => _LoadingScreenState();
double MyMarginAsDouble;
double latitude,longitude;
class _LoadingScreenState extends State<LoadingScreen>
void initState()//if i call getlocation inside init method it automatically gets the location without the need of a button
super.initState();
getLocationData();
Future<void> getLocationData()
async
WeatherModel weatherModel = WeatherModel();
var weatherData = weatherModel.getLocationWeather();
Navigator.push(context,MaterialPageRoute(builder:(context)
return LocationScreen(
locationWeather: weatherData,//weather data links to networkHelper cls in networking.dart gets the weather info using http package
);
));
@override
Widget build(BuildContext context)
return Scaffold(
body:Center(
child:SpinKitDoubleBounce(
color:Colors.white,
size:100,
)
)
);
Location_screen.dart
import 'dart:convert';
import 'package:clima/services/weather.dart';
import 'package:geolocator/geolocator.dart';
import 'package:flutter/material.dart';
import 'package:clima/utilities/constants1.dart';
import 'package:clima/services/weather.dart';
WeatherModel o = WeatherModel();
class LocationScreen extends StatefulWidget
LocationScreen(this.locationWeather);//yow will be passed WeatherData variable (it contains the info of the weather retrieived frm the http api url) (WeatherData of the loading_Screen).
final locationWeather;//LocationWeather receives the information
@override
_LocationScreenState createState() => _LocationScreenState();
class _LocationScreenState extends State<LocationScreen>
WeatherModel weather = WeatherModel();
int temperature;
double temp;
String weatherIcon;
int condition;
String cityName;
@override
void initState()
super.initState();
updateUi(widget.locationWeather);
void updateUi(dynamic weatherData)
var condition = weatherData['weather'][0]['id'];//api contains id eg 300 for light drizzle and so on
temp = weatherData['main']['temp'];
temperature=temp.toInt();
cityName = weatherData['name'];
weatherIcon =weather.getWeatherIcon(condition);//pass that condition to a method in getWeatherdata
print(temperature);
Future<void> getLocation()
async
LocationPermission permission = await Geolocator.requestPermission();
Position position = await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
print(position);
Widget build(BuildContext context)
return Scaffold(
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('images/location_background.jpg'),
fit: BoxFit.cover,
colorFilter: ColorFilter.mode(
Colors.white.withOpacity(0.8), BlendMode.dstATop),
),
),
constraints: BoxConstraints.expand(),
child: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
FlatButton(
onPressed: () async
var weatherData = await weather.getLocationWeather();//we need to gaurantee that this wont return null as it will take long time to execute
updateUi(weatherData);
,
child: Icon(
Icons.near_me,
size: 50.0,
),
),
FlatButton(
onPressed: () ,
child: Icon(
Icons.location_city,
size: 50.0,
),
),
],
),
Padding(
padding: EdgeInsets.only(left: 15.0),
child: Row(
children: <Widget>[
Text(
'$temperature°',
style: kTempTextStyle,
),
Text(
weatherIcon ,
style: kConditionTextStyle,
),
],
),
),
Padding(
padding: EdgeInsets.only(right: 15.0),
child: Text(
"$o.getMessage(temperature)in $cityName!",//
textAlign: TextAlign.right,
style: kMessageTextStyle,
),
),
],
),
),
),
);
Location.dart
导入'package:geolocator/geolocator.dart';
class location
double latitude;
double longitude;
Future getCurrentLocation()
async
try
LocationPermission permission = await Geolocator.requestPermission();
Position position = await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.low); //high is battery consuming
LocationPermission permission1 = await Geolocator.checkPermission();
latitude=position.latitude;
longitude=position.longitude;
catch(e)
print(e);
Networking.dart
import 'package:http/http.dart' as http;
import 'dart:convert';
class NetworkHelper
NetworkHelper(this.url);
var url;
Future getData() async
//var url = Uri.parse(url);
//var url = Uri.parse('api.openweathermap.org/data/2.5/weather?q=London&appid=92e463e61258ef5a8b9a9bd11733b62c');
http.Response response = await http.get(Uri.parse(url));
if (response.statusCode == 200)
String data = response.body;
var decodedData = jsonDecode(data);
return decodedData;
else
print(response.statusCode);
天气.dart
import '../location.dart';
import 'networking.dart';
class WeatherModel
Future getLocationWeather()
async
location ob= new location();
await ob.getCurrentLocation();
print(ob.latitude);
print(ob.longitude);
//calling networkHelper
NetworkHelper networkHelper = NetworkHelper('http://api.openweathermap.org/data/2.5/weather?lat=$ob.latitude&lon=$ob.longitude&appid=92e463e61258ef5a8b9a9bd11733b62c&units=metric');
var WeatherData = await networkHelper.getData();
return WeatherData;
String getWeatherIcon(int condition)
if (condition < 300)
return '????';
else if (condition < 400)
return '????';
else if (condition < 600)
return '☔️';
else if (condition < 700)
return '☃️';
else if (condition < 800)
return '????';
else if (condition == 800)
return '☀️';
else if (condition <= 804)
return '☁️';
else
return '????';
String getMessage(int temp)
if (temp > 25)
return 'It\'s ???? time';
else if (temp > 20)
return 'Time for shorts and ????';
else if (temp < 10)
return 'You\'ll need ???? and ????';
else
return 'Bring a ???? just in case';
city_Screen.dart
import 'package:flutter/material.dart';
import 'package:clima/utilities/constants1.dart';
class CityScreen extends StatefulWidget
@override
_CityScreenState createState() => _CityScreenState();
class _CityScreenState extends State<CityScreen>
@override
Widget build(BuildContext context)
return Scaffold(
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('images/city_background.jpg'),
fit: BoxFit.cover,
),
),
constraints: BoxConstraints.expand(),
child: SafeArea(
child: Column(
children: <Widget>[
Align(
alignment: Alignment.topLeft,
child: FlatButton(
onPressed: () ,
child: Icon(
Icons.arrow_back_ios,
size: 50.0,
),
),
),
Container(
padding: EdgeInsets.all(20.0),
child: null,
),
FlatButton(
onPressed: () ,
child: Text(
'Get Weather',
style: kButtonTextStyle,
),
),
],
),
),
),
);
Conststants1.dart
import 'package:flutter/material.dart';
const kTempTextStyle = TextStyle(
fontFamily: 'Spartan MB',
fontSize: 100.0,
);
const kMessageTextStyle = TextStyle(
fontFamily: 'Spartan MB',
fontSize: 60.0,
);
const kButtonTextStyle = TextStyle(
fontSize: 30.0,
fontFamily: 'Spartan MB',
);
const kConditionTextStyle = TextStyle(
fontSize: 100.0,
);
【问题讨论】:
您在initState
中使用 Future,根据 Flutter 框架这是不正确的。在某处提取该方法,然后在 initState
中调用它
@Hamza 我已经在 init 语句之外编写了 getLocationData 方法,并在 init 状态下调用它。我没明白你想说什么。你能解释一下吗?
【参考方案1】:
像这样更改您的 getLocationData 方法:
getLocationData() async
WeatherModel weatherModel = WeatherModel();
var weatherData = await weatherModel.getLocationWeather();
if (weatherData != null)
Navigator.push(context, MaterialPageRoute(builder: (context)
return LocationScreen(
locationWeather: weatherData,
);
));
【讨论】:
以上是关于错误:在构建期间调用了 setState() 或 markNeedsBuild()的主要内容,如果未能解决你的问题,请参考以下文章
Flutter 错误 - 在构建期间调用了 setState() 或 markNeedsBuild()
Flutter:在构建期间调用 setState() 或 markNeedsBuild()
Flutter - 在构建期间调用 setState() 或 markNeedsBuild()
在构建期间调用 setState() 或 markNeedsBuild() - Flutter
(在构建时出现错误)在构建期间调用 setState() 或 markNeedsBuild()。相关的导致错误的小部件是 MaterialApp