flutter 在initState完成之前运行生成方法

prdp8dxp  于 2023-01-27  发布在  Flutter
关注(0)|答案(1)|浏览(204)

我想用Flutter做一个天气应用程序。但是由于某些原因,()方法在initState之前运行()方法完成。问题是,所有的状态变量都使用setState初始化initState内部的()方法(),其变量将在生成中使用()方法。我猜问题是Flutter试图在setState()方法之前访问那些状态变量,这一直向我抛出错误:一个非空字符串必须提供给一个文本部件。我知道这些代码太长阅读。但我会很感激,如果你能帮助我。

import 'package:flutter/material.dart';

import "package:climat/screens/LoadingScreen.dart";
import "package:climat/screens/MainScreen.dart";
import "package:climat/screens/SearchScreen.dart";

void main() {
  runApp(
    MaterialApp(
      theme: ThemeData(
        fontFamily: "Open Sans",
      ),
      title: "Climat",
      initialRoute: "/",
      onGenerateRoute: (RouteSettings routeSettings) {
        dynamic routes = <String, WidgetBuilder>{
          "/": (context) => LoadingScreen(),
          "/index": (context) => MainScreen(),
          "/search": (context) => SearchScreen(),
        };
        WidgetBuilder builder = routes[routeSettings.name];
        return MaterialPageRoute(builder: (context) => builder(context));
      },
    ),
  );
}
import "package:flutter/material.dart";
import "package:flutter_spinkit/flutter_spinkit.dart";

import "package:climat/services/GeolocatorHelper.dart";
import "package:climat/services/NetworkHelper.dart";

import "package:climat/utilities/constants.dart";

class LoadingScreen extends StatefulWidget {
  @override
  _LoadingScreenState createState() => _LoadingScreenState();
}

class _LoadingScreenState extends State<LoadingScreen> {
  Future<void> getWeatherData() async {
    Map<String, double> coordinates = await GeolocatorHelper().getGeoData();
    final NetworkHelper networkHelper = NetworkHelper(
        uri:
            "$endPoint&lat=${coordinates["latitude"]}&lon=${coordinates["longitude"]}");
    final dynamic data = await networkHelper.getData();
    return await Navigator.pushNamed(context, "/index", arguments: data);
  }

  @override
  void initState() {
    this.getWeatherData();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Climat"),
      ),
      body: SafeArea(
        child: Center(
          child: SpinKitRing(
            color: Colors.redAccent,
          ),
        ),
      ),
    );
  }
}
import "package:flutter/material.dart";

import "package:climat/services/WeatherHelper.dart";
import "package:climat/services/NetworkHelper.dart";

import "package:climat/utilities/constants.dart";

class MainScreen extends StatefulWidget {
  @override
  _MainScreenState createState() => _MainScreenState();
}

class _MainScreenState extends State<MainScreen> {
  Color backgroundColor;
  String cityName;
  int temperature;
  String status;
  String image;
  int minTemperature;
  int maxTemperature;
  int humidity;

  Future<void> updateUI({String userInput = null}) async {
    dynamic weatherData;
    if (userInput == null) {
      weatherData = ModalRoute.of(context).settings.arguments;
    } else {
      final NetworkHelper networkHelper =
          NetworkHelper(uri: "$endPoint&q=$userInput");
      weatherData = await networkHelper.getData();
    }
    final int weatherCode = weatherData["weather"][0]["id"];
    final WeatherHelper weatherHelper = WeatherHelper(
      weatherCode: weatherCode,
    );
    setState(() {
      this.backgroundColor = weatherHelper.getBackgroundColor();
      this.cityName = weatherData["name"];
      this.temperature = weatherData["main"]["temp"].toInt();
      this.status = weatherHelper.getWeatherStatus();
      this.minTemperature = weatherData["main"]["temp_min"].toInt();
      this.maxTemperature = weatherData["main"]["temp_max"].toInt();
      this.humidity = weatherData["main"]["humidity"];
      this.image = weatherHelper.getWeatherImage();
    });
  }

  @override
  void initState() {
    this.updateUI();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: this.backgroundColor,
      appBar: AppBar(
        title: Text("Climat"),
      ),
      body: SafeArea(
        child: Center(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              Text(
                this.cityName,
                style: TextStyle(
                  fontSize: 24.0,
                  color: Colors.white,
                ),
              ),
              SizedBox(
                height: 30.0,
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Image.asset(
                    "./assets/images/${this.image}",
                    scale: 4.0,
                  ),
                  SizedBox(
                    width: 30.0,
                  ),
                  Text(
                    "${this.temperature}°C",
                    style: TextStyle(
                      fontSize: 96.0,
                      color: Colors.white,
                    ),
                  ),
                ],
              ),
              SizedBox(
                height: 30.0,
              ),
              Text(
                this.status.toUpperCase(),
                style: TextStyle(
                  fontSize: 24.0,
                  color: Colors.white,
                ),
              ),
              SizedBox(
                height: 10.0,
              ),
              Text(
                "MIN / MAX : ${this.minTemperature.toString()} / ${this.maxTemperature.toString()}",
                style: TextStyle(
                  fontSize: 24.0,
                  color: Colors.white,
                ),
              ),
              SizedBox(
                height: 10.0,
              ),
              Text(
                "HUMIDITY : ${this.humidity}%",
                style: TextStyle(
                  fontSize: 24.0,
                  color: Colors.white,
                ),
              ),
              SizedBox(
                height: 30.0,
              ),
              ElevatedButton(
                onPressed: () async {
                  dynamic userInput =
                      await Navigator.pushNamed(context, "/search");
                  this.updateUI(
                    userInput: userInput.toString(),
                  );
                },
                style: ElevatedButton.styleFrom(
                  padding: EdgeInsets.symmetric(
                    vertical: 8.0,
                    horizontal: 16.0,
                  ),
                ),
                child: Text(
                  "Search by city name",
                  style: TextStyle(
                    fontSize: 20.0,
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
py49o6xq

py49o6xq1#

如果您希望在initState中使用Future函数,并希望它在build之前运行一次并完成,请考虑使用WidgetsBinding.instance.addPostFrameCallback,例如

@override
void initState() {
    WidgetsBinding.instance.addPostFrameCallback((_) async {
        await this.getWeatherData();
        setState(() { });
    });
}

以及

@override
void initState() {
  WidgetsBinding.instance.addPostFrameCallback((_) async {
    await this.updateUI();
    setState(() { });        
  });
}

应使用setState重建小部件

相关问题