在 initState 中获取一次数据
本课属于 Coddy Flutter 学习旅程的“数据与网络”单元。第 7 课,共 27 课。
每次屏幕重绘时,Flutter 都会再次调用 build:每次调用 setState 后、手机旋转时、父组件发生变化时都如此。一秒内可能调用很多次。build 只应该描述屏幕,绝不能启动任务。
所以,写在 build 里的 fetch 会在每次重绘时再次运行。每次运行都会向服务器发送一个新请求,而当没有任何操作要求获取新结果时,屏幕上的答案也可能突然改变:
// 每次重绘都会发起新请求
FutureBuilder<String>(
future: fetch('/tip'),
...
)在屏幕打开时,于 initState 中创建一次 future,并在每次构建时都将同一个 future 传给 FutureBuilder:
late Future<String> _tip;
@override
void initState() {
super.initState();
_tip = fetch('/tip');
}initState 只会在第一次 build 之前运行一次。按照 Flutter 的要求,用 super.initState(); 启动它。
挑战
中等点击顶部栏中的心形图标:提示内容会改变,因为 fetch 在 build 中。只加载一次提示内容:
- 将
late Future<String> _tip;添加到状态中 - 在
initState中使用fetch('/tip')设置它 - 将
_tip传给FutureBuilder
亲手试试
import 'package:flutter/material.dart';
import 'api.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: TipScreen(),
);
}
}
class TipScreen extends StatefulWidget {
const TipScreen({super.key});
@override
State<TipScreen> createState() => _TipScreenState();
}
class _TipScreenState extends State<TipScreen> {
bool liked = false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Tip of the Day'),
actions: [
IconButton(
icon: Icon(liked ? Icons.favorite : Icons.favorite_border),
onPressed: () {
setState(() {
liked = !liked;
});
},
),
],
),
body: Center(
child: Padding(
padding: const EdgeInsets.all(24),
child: FutureBuilder<String>(
future: fetch('/tip'),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(
snapshot.data!,
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 24),
);
}
return const CircularProgressIndicator();
},
),
),
),
);
}
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
数据与网络中的所有课
自己练习: Flutter 在线编译器