flutter中的网络请求数据获取详解
前端那些年 人气:0跨平台的http请求
http
包提供了最简单的发起请求的方式,并且这个包在WEB
,ANDROID
,IOS
上都得到了很好的支持。
需要注意的是,在某些特定的平台上需要设置一些额外的内容,比如:
在ANDROID
上必须在manifest(AndroidManifest.xml
)文件中进行声明。
<manifest xmlns:android...> ... <uses-permission android:name="android.permission.INTERNET" /> <application ... </manifest>
macOS上必须在.entitlements
进行配置。
<key>com.apple.security.network.client</key> <true/>
请求数据
从网络上请求数据大致分为四步:
- 添加
http
包 - 通过
http
包发起请求 - 将收到的响应数据转为客户端可用的数据
- 展示用户界面
添加http包
我们只需要在pub.dev
文件中添加配置即可:
dependencies: http: <latest_version>
然后在代码中导入http
包:
import 'package:http/http.dart' as http;
另外,在安卓中我们需要添加网络权限:
<!-- Required to fetch data from the internet. --> <uses-permission android:name="android.permission.INTERNET" />
发起请求
发起请求很简单:
Future<http.Response> fetchAlbum() { return http.get(Uri.parse('https://jsonplaceholder.typicode.com/albums/1')); }
http.get()
方法返回一个Future
类的数据,这个数据包含了收到的响应数据。 Future
是用于处理异步操作的核心Dart类。Future
对象表示将来某个时间可能出现的值或错误。 http.Response
类包含从成功的http调用接收的数据。
将响应转为常用对象
虽然发出网络请求很容易,但使用原始的Future<http.Response>
并不是很方便。为了让我们的开发更简单,我们可以将http.Response
转换为Dart对象。
首先,创建一个包含网络请求数据的Album
类。它包括一个工厂构造函数,用于从JSON创建Album。
class Album { final int userId; final int id; final String title; const Album({ required this.userId, required this.id, required this.title, }); factory Album.fromJson(Map<String, dynamic> json) { return Album( userId: json['userId'], id: json['id'], title: json['title'], ); } }
然后,我们使用以下步骤更新fetchAlbum()
函数以返回Future<Album>
:
- 使用
dart:Convert
包将响应体转换为JSON映射。 - 如果服务器确实返回了状态代码为
200
的OK响应,则使用fromJson()
工厂方法将JSON映射转换为Album
。 - 如果服务器没有返回状态代码为200的OK响应,则抛出异常。(即使在“404 Not Found”服务器响应的情况下,也会抛出异常。不要返回null。这在检查快照中的数据时很重要,如下所示。)
Future<Album> fetchAlbum() async { final response = await http .get(Uri.parse('https://jsonplaceholder.typicode.com/albums/1')); if (response.statusCode == 200) { // If the server did return a 200 OK response, // then parse the JSON. return Album.fromJson(jsonDecode(response.body)); } else { // If the server did not return a 200 OK response, // then throw an exception. throw Exception('Failed to load album'); } }
获取数据
我们可以在initState()
或didChangeDependencies()
方法中调用fetchAlbum()
方法。
initState()
方法只调用一次,然后再也不会调用。如果我们想选择重新加载API以响应InheritedWidget
的更改,我们可以将调用放入didChangeDependencies()
方法中。
class _MyAppState extends State<MyApp> { late Future<Album> futureAlbum; @override void initState() { super.initState(); futureAlbum = fetchAlbum(); } // ··· }
展示数据
要在屏幕上显示数据,我们可以使用FutureBuilder
组件。FutureBuilder
组件随Flutter一起提供,可以轻松处理异步数据源。
我们需要提供两个参数:
- 具体的Future
- builder方法,用来告诉系统渲染什么内容,根据状态可以选择
加载中
等等。
FutureBuilder<Album>( future: futureAlbum, builder: (context, snapshot) { if (snapshot.hasData) { return Text(snapshot.data!.title); } else if (snapshot.hasError) { return Text('${snapshot.error}'); } // By default, show a loading spinner. return const CircularProgressIndicator(); }, )
为什么要在initstate中获取数据?
虽然在build()中调用很方便,但不建议将API调用放在build()方法中。
Flutter每次需要更改视图中的任何内容时都会调用build()
方法,这种情况经常发生。如果将fetchAlbum()
方法放置在build()
中,则会在每次重建时重复调用,导致应用程序速度减慢。
加载全部内容