我需要在應用程式啟動時發出 http 請求并將值保存在小部件中,以便在子小部件中使用它,但我無法使其作業。我正在使用 InitState() 發出請求,但我無法保存和使用該值。
這是我現在的代碼。我得到的錯誤是 WeatherObject 作為 MainWeatherCardWidget 的引數不能為空,我同意,但如果我理解正確,那么 fetchData() 中的 await 鍵盤不應該等到 http 請求完成嗎?還是我誤解了什么?
可選的變數可能是關鍵,但我需要制作它,因為我需要在初始化后將值保存在其中,并且我無法從 InitState() 回傳某些內容。
我認為它可能適用于 Provider 包,但我不想在這個專案中使用它,因為我認為不需要全域狀態。無論如何,如何實作呢?
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
CurrentWeatherInterface? weatherObject;
Future<void> fetchData() async {
weatherObject = await fetchCurrentWeather(dotenv.env['API_KEY']);
}
@override
void initState() {
super.initState();
// fetch weather data
fetchData();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(
preferredSize:
Size.fromHeight(MediaQuery.of(context).size.height * 0.075),
child: AppBar(
backgroundColor: Colors.transparent,
elevation: 0.0,
),
),
drawer: const Drawer(),
backgroundColor: const Color.fromRGBO(62, 149, 250, 1),
body: SingleChildScrollView(
child: Center(
child: SizedBox(
width: MediaQuery.of(context).size.width * 0.85,
child: Column(
children: [
MainWeatherCardWidget(
weatherObject: weatherObject!,
),
const HourlyWeatherCardListWidget(),
const DailyWeatherListCardWidget(),
],
),
),
),
),
);
}
}
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:weather_app/interfaces/current_weather_interface.dart';
Future<CurrentWeatherInterface> fetchCurrentWeather(String? APIKey) async {
const url =
'http://api.weatherapi.com/v1/current.json?key=729fc1d266eb46589bf122819222505&q=Ararangua&qi=no';
final response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
return CurrentWeatherInterface.fromJson(jsonDecode(response.body));
} else {
throw Exception('Failed to fetch data');
}
}
uj5u.com熱心網友回復:
您是正確的, await 關鍵字會使 http fetch 等待直到完成。但是不等待在您的 initState 中呼叫 fetchData 的方法。所以 build 會在 initState 完成時運行,無需等待 fetchData。因此,該值仍將為空,并且您會收到錯誤訊息。
此外,您不能在 initState 中等待它,因為這不是異步的。因此,請查看命名的小部件并將FutureBuilder其與 fetchData 作為未來引數一起使用。
所以FutureBuilder使用fetchData和MainWeatherCardWidget
uj5u.com熱心網友回復:
不允許呼叫它await,您需要像這樣使用:initstateFutureBuilder
FutureBuilder<CurrentWeatherInterface>(
future: fetchData(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Text('Loading....');
default:
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
weatherObject = snapshot.data!;
return SingleChildScrollView(
child: Center(
child: SizedBox(
width: MediaQuery.of(context).size.width * 0.85,
child: Column(
children: [
MainWeatherCardWidget(
weatherObject: weatherObject!,
),
const HourlyWeatherCardListWidget(),
const DailyWeatherListCardWidget(),
],
),
),
),
);
}
}
},
)
uj5u.com熱心網友回復:
在構建小部件 MainWeatherCardWidget 時,您正在對 weatherObject 使用空檢查 (!)。但是,weatherObject 僅在 fetchData() 執行后才被初始化。在那之前,weatherObject 只不過是 null。這就是導致空錯誤的原因。
并且在 fetchData() 定義中使用 await 是錯誤的。它只會讓 fetchData() 函式中的代碼在繼續之前等待。但是 fetchData() 本身在 initState() 內部被異步呼叫。因此,在構建小部件時, fetchData() 內部的 await 不會有太大幫助。
現在,要解決這個問題,有兩種選擇。
初始化weatherObject:為此,為CurrentWeatherInterface定義一個建構式,如果它還沒有的話。并使用
CurrentWeatherInterface weatherObject = CurrentWeatherInterface()而不是簡單地宣告weatherObject。這樣,小部件將有一個適當的非空物件來構建小部件。這種方法將更容易實作。更少的代碼行。
讓小部件正確處理 null:為此,更改 MainWeatherCardWidget 的定義,使引數可以為 null。在其定義中,無論在何處使用該引數,都要安排如何處理 null 情況。例如,如果要在 UI 中給出加載指示,則
Text(weatherObject.placeName)必須替換為此Text(weatherObject == null ? "loading" : weatherObject.placeName)方法會更好。
此外,請確保使用 setState 將代碼包裝在 fetchData() 中。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/523350.html
標籤:扑
