我已經閱讀了 Flutter 中有關 Futures 的大部分檔案。但我仍然不明白如何從函式回傳一個沒有未來的值。
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() => runApp( Kitchen());
class Kitchen extends StatelessWidget {
String caption = '-none-';
Kitchen({Key? key}) : super(key: key);
String retrieve() async {
const String link = 'http://worldclockapi.com/api/json/utc/now';
Uri url = Uri.parse(link);
http.Response response = await http.get(url);
String result = response.toString();
return result;
}
@override
Widget build(BuildContext context) {
caption = retrieve();
return MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
appBar: AppBar(title: const Text('Kitchen async demo') )
, body: Container(
color: Colors.cyan[50]
, child: Center( child: Text(caption) )
)
)
);
}
}
代碼不會運行,因為retrieve 的回傳型別必須是Future 所寫的。如果我永遠不能從這個函式回傳任何東西,除了一個 Future,為什么還要使用 await 關鍵字呢?為什么 await 陳述句的回傳型別不是 Future。我不明白。
uj5u.com熱心網友回復:
我喜歡將未來視為“即將成為的價值”。
期貨可以(并且應該!)有一個型別引數來解釋未來最終會是什么(如果未來永遠不會是未來,你可以使用 void )
Future<String> someLongComputation() async { ... }
上面,someLongComputation將立即回傳一個未來,一段時間后,未來將用一個字串決議。
await 關鍵字所做的是等到未來回傳一個值然后回傳該值,基本上將異步計算轉換為同步計算,當然這首先否定了使其異步的全部意義,所以 await關鍵字只能在另一個異步函式內部使用。
你不能從異步函式回傳一個字串,一個字串必須立即有一個值,但異步函式永遠不會立即有一個值,你應該做的是回傳一個未來的字串:
Future<String> retrieve() async {
const String link = 'http://worldclockapi.com/api/json/utc/now';
Uri url = Uri.parse(link);
http.Response response = await http.get(url);
String result = response.toString();
return result;
}
但這是一個問題,因為您正試圖在小部件上顯示字串。您希望在函式運行時看到什么?如果您沒有互聯網并且該功能卡住了一分鐘怎么辦?
你有幾個選擇:
您可以使用 setState 和有狀態的小部件:
class Kitchen extends StatefulWidget{
...
}
class _KitchenState extends State<Kitchen> {
String caption = '-none-';
Kitchen({Key? key}) : super(key: key);
Future<void> retrieve() async {
const String link = 'http://worldclockapi.com/api/json/utc/now';
Uri url = Uri.parse(link);
http.Response response = await http.get(url);
String result = response.toString();
setState(() => caption = result);
}
@override
initState() {
super.initState();
retrieve();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
appBar: AppBar(title: const Text('Kitchen async demo') )
, body: Container(
color: Colors.cyan[50]
, child: Center( child: Text(caption) )
)
)
);
}
}
如您所見,我洗掉了回傳型別并將其更改為對 的呼叫setState,我還在 initstate 上呼叫該函式,而不是build.
您的第二個選項是FutureBuilder用來完成類似的事情:
class Kitchen extends StatelessWidget {
Kitchen({Key? key}) : super(key: key);
Future<String> retrieve() async {
const String link = 'http://worldclockapi.com/api/json/utc/now';
Uri url = Uri.parse(link);
http.Response response = await http.get(url);
String result = response.toString();
return result;
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: retrieve(),
builder: (context, snapshot) {
final caption = snapshot.data ?? '-none-';
return MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
appBar: AppBar(title: const Text('Kitchen async demo') ),
body: Container(
color: Colors.cyan[50],
child: Center( child: Text(caption) )
)
)
);
}
);
}
The code above might look ugly, but all you have to understand is that the FutureBuilder widget takes two arguments: future and builder, future is just the future you want to use, while builder is a function that takes two parameters and returns a widget. FutureBuilder will run this function before and after the future completes. The two arguments are the current context and a snapshot, which has some useful things:
You can access the future's result with snapshot.data, if the future has not yet completed, it will be null!
You can also see if there is data with snapshot.hasData.
You can see if something went wrong with snapshot.hasError and snapshot.error.
Finally, you can see the state of the future with snapshot.connectionState, which may have one of 4 values:
- none, maybe with some initial data.
- 等待,表示異步操作已經開始,通常資料為空。
- 活動,資料不為空,并且可能隨時間變化。
- 完成,資料不為空。
以檢查使用if (snapshot.connectionState == ConnectionState.done)為例。
為了更好地理解snapshot和理解FutureBuilder,您可以查看檔案:
快照(其實叫異步快照):https : //api.flutter.dev/flutter/widgets/AsyncSnapshot-class.html
未來構建器:https : //api.flutter.dev/flutter/widgets/FutureBuilder-class.html
uj5u.com熱心網友回復:
這是一個在螢屏中間列印當前時間的作業示例。創建初始小部件時,它將列印 -none- 然后一旦未來完成,它將生成當前日期和時間。這一切都基于上面的答案。
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() => runApp( Kitchen());
class Kitchen extends StatefulWidget{
Kitchen( {Key? key,}) : super(key: key);
@override
_KitchenState createState(){
return _KitchenState();
}
}
class _KitchenState extends State<Kitchen> {
String caption = '-none-';
Future<void> retrieve() async {
const String link = 'http://worldclockapi.com/api/json/utc/now';
Uri url = Uri.parse(link);
http.Response response = await http.get(url);
Map body = json.decode( response.body );
String result = body['currentDateTime'];
setState(() => caption = result);
}
@override
initState() {
super.initState();
retrieve();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
appBar: AppBar(title: const Text('Kitchen async demo') )
, body: Container(
color: Colors.cyan[50]
, child: Center( child: Text(caption) )
)
)
);
}
}
uj5u.com熱心網友回復:
基于第一個答案的作業 futureBuilder 示例。就像 initState 版本一樣作業。
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() => runApp( Kitchen());
class Kitchen extends StatefulWidget{
Kitchen( {Key? key,}) : super(key: key);
@override
_KitchenState createState(){
return _KitchenState();
}
}
class _KitchenState extends State<Kitchen> {
Future<String> retrieve() async {
const String link = 'http://worldclockapi.com/api/json/utc/now';
Uri url = Uri.parse(link);
http.Response response = await http.get(url);
Map body = json.decode( response.body );
String result = body['currentDateTime'];
return result;
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: retrieve(),
builder: (context, snapshot) {
final caption = snapshot.data ?? '-none-';
return MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
appBar: AppBar(title: const Text('Kitchen async demo') ),
body: Container(
color: Colors.cyan[50],
child: Center( child: Text( caption.toString() ) )
)
)
);
}
);
}
}
uj5u.com熱心網友回復:
帶有進度指示器的作業示例。我猜一種做裝載機的方法。
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() => runApp( Kitchen());
class Kitchen extends StatefulWidget{
Kitchen( {Key? key,}) : super(key: key);
//===================================================
// createState =
//===================================================
@override
_KitchenState createState(){
return _KitchenState();
}
}
class _KitchenState extends State<Kitchen> {
Future<bool> wasteTime() {
return Future.delayed(const Duration(seconds: 2)).then((onValue) => true);
}
Future<String> retrieve() async {
const String link = 'http://worldclockapi.com/api/json/utc/now';
Uri url = Uri.parse(link);
http.Response response = await http.get(url);
Map body = json.decode( response.body );
String result = body['currentDateTime'];
// here only to show the CircularProgressIndicator to the user.
// The network calls are fairly quick.
await wasteTime();
return result;
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: retrieve(),
builder: (context, snapshot) {
if( snapshot.connectionState == ConnectionState.done
&& snapshot.hasError )
{
return MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
appBar: AppBar(title: const Text('Kitchen async demo') ),
body: Container(
color: Colors.cyan[50],
child: const Center( child: Text( 'Error message' ) )
)
)
);
}
else if( snapshot.connectionState == ConnectionState.done
&& snapshot.hasData )
{
final caption = snapshot.data ?? '-none-';
return MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
appBar: AppBar(
title: const Text('Kitchen async demo')
),
body: Container(
color: Colors.cyan[50],
child: Center(
child: Text( caption.toString() )
)
)
)
);
}
else {
return MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
appBar: AppBar(title: const Text('Kitchen async demo') ),
body: Container(
color: Colors.cyan[50],
child: const Center(
child: CircularProgressIndicator(
value: null, color: Colors.blue
)
)
)
)
);
}
}
);
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/420300.html
標籤:
上一篇:如何添加水平滾動條顫動
