问题描述
我正在开发一个 Flutter 应用程序,我使用 ChangeNotifierProvider 来管理状态。我有一个名为“Data”的类,它是应用程序的模型(MVC 设计模式中的模型)和一个名为“DataManager”的类,它是应用程序的模型是应用程序的控制器(MVC 设计模式中的控制器)并在其中创建一个 Data 实例。 我在我的 main 中创建了 ChangeNotifierProvider 的实例,ChangeNotifier 是 DataManager。所以DataManager 中的方法调用notifyListeners() 方法。 当我运行应用程序时,我添加了一个磁贴,尽管添加了磁贴,但它的 UI 不会改变。添加另一个磁贴后,第一个磁贴出现,依此类推。应用程序始终落后于用户一个级别。 你能帮我解决这个问题吗?
这是 main.dart:
main(){
runApp(MyApp());
}
class MyApp extends StatefulWidget{
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => DataManager(),child: MaterialApp(
home: LoadingScreen()
),);
}
}
这是 Data.dart(这里的方法可能并不重要):
class Data{
Position _location;
List<CityTile> _cityWidgets = List<CityTile>();
List<Weather> _weatherDatas = List<Weather>();
Future<Position> getLocation() async {
bool serviceEnabled;
LocationPermission permission;
serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
print('Location services are disabled.');
return Future.error('Location services are disabled.');
}
permission = await Geolocator.checkPermission();
if (permission == LocationPermission.deniedForever) {
print('Location permissions are permanently denied,we cannot request permissions.');
return Future.error(
'Location permissions are permanently denied,we cannot request permissions.');
}
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission != LocationPermission.whileInUse &&
permission != LocationPermission.always) {
print( 'Location permissions are denied (actual value: $permission).');
return Future.error(
'Location permissions are denied (actual value: $permission).');
}
}
_location = await Geolocator.getCurrentPosition();
return _location;
}
void addCity({Weather cityWeather}) async{
bool isReady = await cityWeather.updateWeather();
String cityName = cityWeather.getCity;
if(!cityExists(cityName) && isReady) {
_weatherDatas.add(cityWeather);
_cityWidgets.add(CityTile(cityName));
}
// print("widgets:");
// for(CityTile cityTile in _cityWidgets){
// print("${cityTile.city} widget exists");
// }
// print("weathers:");
// for(Weather weather in _weatherDatas){
// print("${weather.getCity} weather exists");
// }
}
Weather searchWeather({String cityName}){
for(Weather weather in _weatherDatas){
if(weather.getCity == cityName){
return weather;
}
}
return null;
}
bool cityExists(String cityName){
if(searchWeather(cityName: cityName) == null)
return false;
else
return true;
}
void removeCity({String cityName}) {
if (cityExists(cityName)) {
_removeCityWidget(cityName: cityName);
_removeCityWeather(cityName: cityName);
}
}
void _removeCityWidget({String cityName}){
CityTile cityTiletoRemove;
for(CityTile cityTile in _cityWidgets){
if(cityTile.city == cityName){
cityTiletoRemove = cityTile;
}
}
if(cityTiletoRemove != null)
_cityWidgets.remove(cityTiletoRemove);
}
void _removeCityWeather({String cityName}){
Weather weather = searchWeather(cityName: cityName);
if(weather != null)
_weatherDatas.remove(weather);
}
int widgetNumbers(){
return _cityWidgets.length;
}
get weatherDatas{
return List.unmodifiable(_weatherDatas);
}
get cityWidgets{
return List.unmodifiable(_cityWidgets);
}
}
这是 DataManager.dart:
class DataManager extends ChangeNotifier{
Data data = Data();
Future<bool> findWeatherByLocation() async{
Position location = await data.getLocation();
// print("long : ${location.longitude} and lat : ${location.latitude}");
Weather weatherOfhere = Weather(city: null);
String weatherCast = "";
if(location == null){
// print("location is null");
return false;
}
for(int i=0; i<5; i++){
weatherCast = await weatherOfhere.getCurrentWeather(location: location);
if(weatherCast.isNotEmpty)
break;
}
if( weatherCast.isEmpty || jsonDecode(weatherCast)['cod'] == '404') {
// print("city not found");
return false;
}
// print("weathercast : $weatherCast");
addCityByWeather(weatherOfhere);
return true;
}
void addCityByWeather(Weather cityWeather){
data.addCity(cityWeather: cityWeather);
notifyListeners();
}
void addCityByName(String city) async{
if(!data.cityExists(city) && city.isNotEmpty){
Weather cityWeather = Weather(city: city);
bool isRealCity = await cityWeather.updateWeather();
if(isRealCity) {
data.addCity(cityWeather: cityWeather);
}
}
notifyListeners();
}
void removeCity(String city){
data.removeCity(cityName: city);
notifyListeners();
}
int cityNumbers(){
return data.widgetNumbers();
}
Future<bool> updateWeather(String city) async{
Weather weatherToUpdate = data.searchWeather(cityName: city);
bool isUpdated = false;
if(weatherToUpdate == null){
return false;
}
else{
isUpdated = await weatherToUpdate.updateWeather();
notifyListeners();
}
return isUpdated;
}
get weatherDatas{
return data.weatherDatas;
}
get cityWidgets{
return data.cityWidgets;
}
void addOption(String option){
option = option.toLowerCase() == 'feels like' ? 'feels_like' : option;
options[option.toLowerCase()] = true;
//updateall();
notifyListeners();
}
void removeOption(String option){
option = option.toLowerCase() == 'feels like' ? 'feels_like' : option;
options[option.toLowerCase()] = false;
// updateall();
notifyListeners();
}
void updateall(){
for(Weather weather in data.weatherDatas)
weather.updateWeather();
notifyListeners();
}
bool isOptionSelected(String option){
option = option.toLowerCase() == 'feels like' ? 'feels_like' : option;
// print("in isOptionSelected: ${options[option.toLowerCase()]}");
return options[option.toLowerCase()];
}
Color getoptionButtonColor(String option){
option = option.toLowerCase() == 'feels like' ? 'feels_like' : option;
return isOptionSelected(option) ? Colors.indigo : Colors.black38;
}
get getoptions{
return options;
}
String getWeatherScreenPicture(String city){
Weather weatherData = data.searchWeather(cityName: city);
int id = weatherData.id;
if(id == 800){
var Now = new DateTime.Now();
List clearSky = codetoPicture[800];
if( Now.hour> 18 ) {
return clearSky[1];
}else
return clearSky[0];
}
return codetoPicture[id];
}
String getWeatherInfo(String city,String field){
Weather weather = data.searchWeather(cityName: city);
if(weather != null){
switch(field){
case 'temperature':
return weather.temperature;
case 'pressure':
return weather.pressure;
case 'humidity':
return weather.humidity;
case 'weather description':
return weather.weatherDescription;
case 'wind speed':
return weather.windSpeed;
case 'feels_like':
return weather.feelsLike;
}
}
return "null";
}
IconData getWeatherIcon(String city){
Weather weather = data.searchWeather(cityName: city);
if(weather != null)
return weather.icon;
else
return WeatherIcons.refresh;
}
}
还有一个 listView.Builder 可以添加这些图块(城市小部件):
class CitiesScreen extends StatelessWidget {
final TextEditingController _textEditingController = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
bottomNavigationBar: NavigationBar(),backgroundColor: Colors.lightBlue,body: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 20,horizontal: 10),child: Column(
children: <Widget>[
ColorfulBox(
ListTile(
title: TextField(
controller: _textEditingController,style: TextStyle(fontSize: 20,color: Colors.white),),trailing: SizedBox(
width: 100,child: Row(
children: [
SizedBox(
width: 50,child: FlatButton(
child: Icon(Icons.add,size: 30,color: Colors.white,onpressed: () {
Provider.of<DataManager>(context,listen: false).addCityByName(_textEditingController.text);
_textEditingController.clear();
},SizedBox(
width: 50,child: FlatButton(
onpressed: () => Provider.of<DataManager>(context,listen: false).findWeatherByLocation(),child: Icon(Icons.location_on_outlined,)
],SizedBox(height: 30,Expanded(
child: Consumer<DataManager>(
builder: (context,data,child){
return ListView.builder(
shrinkWrap: true,scrollDirection: Axis.vertical,itemCount: Provider.of<DataManager>(context).cityNumbers(),itemBuilder: (context,index) => Provider.of<DataManager>(context).cityWidgets[index],);
},)
],);
}
}
解决方法
插入
Provider.of<DataManager>(context);
构建函数。
它会在您调用 notifyListeners() 并更新 UI 时进行侦听。