Flutter实现网络请求以及加载ListView

动态加载ListView

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import 'package:flutter/material.dart';
import 'dart:io';
import 'dart:convert';
void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(title: Text('Flutter Demo')), body: MyHomeWidget()));
}
}

class MyHomeWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ListView(
children: ListTile.divideTiles(context: context, tiles: [
ListTile(
leading: Image.network(
"https://avatars3.githubusercontent.com/u/6915570?s=460&v=4"),
title: Text('我是标题1'),
subtitle: Text('我是副标题1'),
trailing: Icon(Icons.chevron_right)),
ListTile(
leading: Image.network(
"https://avatars3.githubusercontent.com/u/6915570?s=460&v=4"),
title: Text('我是标题2'),
subtitle: Text('我是副标题2'),
trailing: Icon(Icons.chevron_right)),
ListTile(
leading: Image.network(
"https://avatars3.githubusercontent.com/u/6915570?s=460&v=4"),
title: Text('我是标题3'),
subtitle: Text('我是副标题3'),
trailing: Icon(Icons.chevron_right)),
ListTile(
leading: Image.network(
"https://avatars3.githubusercontent.com/u/6915570?s=460&v=4"),
title: Text('我是标题4'),
subtitle: Text('我是副标题4'),
trailing: Icon(Icons.chevron_right)),
ListTile(
leading: Image.network(
"https://avatars3.githubusercontent.com/u/6915570?s=460&v=4"),
title: Text('我是标题5'),
subtitle: Text('我是副标题5'),
trailing: Icon(Icons.chevron_right)),
]).toList(),
);
}

}

效果

网络请求实现

1.依赖添加

​ 在pubspec.yaml 文件中添加 http请求依赖

1
http: ^0.11.3+17

1.添加http包装

http软件包提供了从Internet提取数据的最简单方法。

要安装该http软件包,请将其添加到pubspec.yaml文件的“ dependencies”部分。您可以找到pub.dev http软件包的最新版本 。

content_copy

1
2
dependencies:
http: <latest_version>

导入http包。

content_copy

1
import 'package:http/http.dart' as http;

2.发出网络请求

本食谱介绍如何使用JSONPlaceholderhttp.get()方法获取样本专辑 。

content_copy

1
2
3
Future<http.Response> fetchAlbum() {
return http.get('https://jsonplaceholder.typicode.com/albums/1');
}

http.get()方法返回Future包含的Response

  • Future是用于处理异步操作的核心Dart类。Future对象表示将来某个时候可用的潜在值或错误。
  • http.Response类包含一个成功的HTTP调用接收到的数据。

3.将响应转换为自定义Dart对象

发出网络请求很容易,但是使用原始 Future<http.Response>操作并不是很方便。为了使您的生活更轻松,请将转换http.Response为Dart对象。

建立Album课程

首先,创建一个Album包含来自网络请求的数据的类。它包括一个Album从JSON 创建一个工厂构造函数。

手动转换JSON只是一种选择。有关更多信息,请参阅JSON和序列化的完整文章 。

content_copy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Album {
final int userId;
final int id;
final String title;

Album({this.userId, this.id, this.title});

factory Album.fromJson(Map<String, dynamic> json) {
return Album(
userId: json['userId'],
id: json['id'],
title: json['title'],
);
}
}

将转换http.ResponseAlbum

现在,使用以下步骤更新该fetchAlbum() 函数以返回a Future<Album>

  1. Map使用dart:convert包将响应主体转换为JSON 。
  2. 如果服务器确实返回了状态代码为200的OK响应,则 使用factory方法将JSON Map转换为。Album``fromJson()
  3. 如果服务器未返回状态码为200的OK响应,则引发异常。(即使在“ 404未找到”服务器响应的情况下,也会引发异常。请勿返回null。这在检查中的数据时很重要snapshot,如下所示。)

content_copy

1
2
3
4
5
6
7
8
9
10
11
12
13
Future<Album> fetchAlbum() async {
final response = await http.get('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(json.decode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}

万岁!现在,您有了一个可以从互联网上获取专辑的功能。

4.提取数据

fetch()initState()didChangeDependencies() 方法中调用方法。

initState()方法仅被调用一次,然后不再调用。如果您希望选择重新加载API以响应 InheritedWidget更改,请将该调用放入 didChangeDependencies()方法中。请参阅State以获取更多详细信息。

content_copy

1
2
3
4
5
6
7
8
class _MyAppState extends State<MyApp> {
Future<Album> futureAlbum;

@override
void initState() {
super.initState();
futureAlbum = fetchAlbum();
}

下一步将使用此Future。

5.显示数据

要在屏幕上显示数据,请使用 FutureBuilder小部件。该FutureBuilder小部件随Flutter一起提供,可轻松使用异步数据源。

您必须提供两个参数:

  1. Future你想要的工作。在这种情况下,将来从fetchAlbum()函数返回。
  2. builder,告诉扑功能呈现什么,取决于状态Future:加载,成功或错误。

请注意,snapshot.hasDatatrue 当快照包含非空数据值时才返回。这就是fetchAlbum即使在“ 404 Not Found”服务器响应的情况下,函数也应引发异常的原因。如果fetchAlbum返回,null 则微调框将无限期显示。

content_copy

1
2
3
4
5
6
7
8
9
10
11
12
13
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 CircularProgressIndicator();
},
);

为什么在initState()中调用fetchAlbum()?

尽管很方便,但不建议将API调用放入build()方法中。

Flutter build()每当需要更改视图中的任何内容时都会调用该方法,并且这种情况经常出乎意料地发生。将fetch调用留在您的build()方法中会使不必要的调用泛滥到API中,并降低您的应用速度。

完整的例子

content_copy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import 'dart:async';
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

Future<Album> fetchAlbum() async {
final response =
await http.get('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(json.decode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}

class Album {
final int userId;
final int id;
final String title;

Album({this.userId, this.id, this.title});

factory Album.fromJson(Map<String, dynamic> json) {
return Album(
userId: json['userId'],
id: json['id'],
title: json['title'],
);
}
}

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
//构造函数 接收值
MyApp({Key key}) : super(key: key);

@override
_MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
Future<Album> futureAlbum;

@override
void initState() {
super.initState();
futureAlbum = fetchAlbum();
}

@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Fetch Data Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text('Fetch Data Example'),
),
body: Center(
child: 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 CircularProgressIndicator();
},
),
),
),
);
}
}

完整效果

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×