在Flutter中消耗API
应用编程接口(API)是一个通信门户,它允许两个或更多的应用程序连接以共享数据。它作为一个中介,向服务提供者传递请求并返回响应。鉴于使用预先存在的框架的便利性,API的使用在移动应用程序开发中得到了普遍的应用。程序员使用大多数API从网络服务器获取数据,并将其渲染到UI组件中。
本文将演示如何在Flutter应用程序中使用RESTful API从服务器获取和消费数据。根据维基百科,Representational State Transfer API是HTTP的一个架构子集,通常用于创建使用网络服务的交互式应用程序。
它允许程序员从服务器上获取和修改资源。REST API是首选,因为它支持大多数协议和数据格式。在本教程中,我们将使用HTTP和JSON数据格式
前提条件
- 对Flutter有一个基本的了解
- 在您的电脑上安装Flutter SDK
- 代码编辑器,最好是Android Studio或VSCode。
- 一个模拟器或一个移动设备来运行代码。
设置应用程序
首先,您需要通过在您的计算机上安装Flutter SDK来设置您的应用程序。安装完SDK后,我们现在需要设置我们的本地机器项目。如果您以前没有使用过flutter,以逐步了解创建flutter项目的情况。
API密钥和客户秘密
我们将在Github API的基础上建立我们的应用程序。因此,我们需要获得GitHubclient key 和secret 来访问API。
整理文件夹
我们需要在Flutter项目中组织文件夹,而不是在单个文件上写代码,以便轻松地找到我们应用程序的文件和组件。这种做法可以让我们更容易找到bug。
此外,我们需要将视图文件与便于从API获取数据的文件分开,以避免这两个应用程序的组件之间的混淆。 最终的文件夹组织应该如下图所示。
lib
┣ models
┃ ┗ User.dart
┣ Providers
┃ ┗ UserProvider.dart
┣ Requests
┃ ┗ GithubRequest.dart
┣ Screens
┃ ┗ FollowersPage.dart
┗ main.dart
添加HTTP包
HTTP package ,其中包含了一组用于HTTP资源消耗的高级函数。要将该包添加到我们的应用程序中,请打开pubspec.yml ,在 "dependencies "下添加以下一行。
dependencies:
flutter:
SDK: flutter
HTTP: ^0.12.2
接下来,我们将用下面这行代码把HTTP包导入我们的GithubRequest.dart 文件中。
import 'package:HTTP/HTTP.dart' as HTTP;
下面的片段显示了我们将如何使用该包从API中获取一个给定的用户名的关注者。我们使用用户名是因为每个用户都有一个独特的用户名。
GithubRequest.dart
//importing HTTP package for fetching and consuming HTTP resources
import 'package:HTTP/HTTP.dart' as HTTP;
//Github request class
class Github {
final String userName; // usernaname
final String url = 'https://api.github.com/';
static String clientId = 'CLIENT_ID'; //enter yout client id
static String clientSecret = 'CLIENT_SECRET'; // insert your client secret
//Github class constructor
Github(this.userName);
//Fetch a user with the username supplied in the form input
Future<http.Response> fetchUser() {
return http.get(url + 'users/' + userName);
}
}
从JSON创建数据类
由于Flutter接受dart作为主要编程语言,我们需要将从URL中获取的JSON数据转换为dart类,以便在应用程序中使用。
我们可以使用Quicktype网站来完成,在那里我们传递JSON对象,并根据指定的语言返回该对象的类。将会以dart ,返回我们的类。
例如,我们代表用户的JSON如下所示。
//data json object
{
"login": "jerimkaura",
"avatar_url": "https://avatars.githubusercontent.com/u/50904889?v=4",
"location": "Nairobi"
}
用户类
我对JSON进行了编辑,只捕获了应用程序上需要的属性。当我们将上述JSON传入Quicktype时,生成的用户类如下。
// To parse this JSON data, do
final user = userFromJson(jsonString);
import 'dart:convert';
//the created user class
class User {
String login; //username
String avatarUrl; //profile picture
String location; //location
//class constructor
User({
this.login, //username
this.avatarUrl, //profile picture
this.location, //location
});
//JSON serialization: return the value from json
factory User.fromRawJson(String str) => User.fromJson(json.decode(str));
//encode data to json format
String toRawJson() => json.encode(toJson());
//creating a dart user object from the json object
factory User.fromJson(Map<String, dynamic> json) => User(
login: json["login"],
avatarUrl: json["avatar_url"],
location: json["location"],
);
Map<String, dynamic> toJson() => {
"login": login,
"avatar_url": avatarUrl,
"location": location,
};
}
添加提供者
提供者将拥有获取API的用户数据和提供响应所需的功能。我们将在Providers 文件夹下创建一个名为UserProvider.dart 的文件。
ChangeNotifier 类将在多一个变量变化时通知我们的视图。当我们的代码继续执行时,我们使用async 函数来等待从API中获取用户的数据。
class UserProvider with ChangeNotifier {
User user; //an instance of a user
String errorMessage; //error message
bool loading = false; //loading the page
Future<bool> fetchUser(username) async {
setLoading(true);
// fetch user from the input supplied in the form
await Github(username).fetchUser().then((data) {
setLoading(false);
if (data.statusCode == 200) {
//incase of success
setUser(User.fromJson(json.decode(data.body)));
} else {
Map<String, dynamic> result = json.decode(data.body);
setMessage(result['message']); // error message
}
});
return isUser(); //returns the fetched user
}
bool isLoading() {
return loading; //return true if the app is loading the data
}
void setLoading(value) {
loading = value;
notifyListeners(); //This method is called when the objects is changed
}
void setUser(value) {
user = value;
notifyListeners(); //alert listeners that user's value changed
}
User getUser() {
return user; //returns the fetched user
}
void setMessage(value) {
errorMessage = value;
notifyListeners(); // alert listeners that the error message changed
}
String getMessage() {
return errorMessage; // get the error message
}
bool isUser() {
return user != null ? true : false; // returns true if user is not null, anf false otherwise
}
}
消耗数据
随着我们的模型和提供者准备就绪,我们的应用程序将通过提供者获取数据,并使用用户模型的方法将JSON结果转换为dart类。
接下来我们要做的是在移动屏幕上消费数据。在这个过程中,我们将做三件主要的事情。
实例化用户类。
我们将有两个用户类的实例;一个是用户的实例,另一个是给定用户的关注者列表。
User user; //instantiate a user
List< User> followers; // instantiate a list of users as a placeholder for the followers.
使用setState()来获取数据
setState方法通知应用程序,应用程序的内部状态已经被改变,并且这种改变可能会影响到视图。我们将在我们的FollowersPage.dart 文件中添加这段代码,就在打开scaffold() widget之前。
setState(() {
//This function gets a user from the username supplied in the input
user = Provider.of<UserProvider>(context).getUser();
// this method returns followers of the username supplied in the input as a list
Github(user.login).fetchFollowers().then((following) {
Iterable list = json.decode(following.body);
setState(() {
followers = list.map((e) => User.fromJson(e)).toList();
});
});
});
在用户界面上渲染数据
数据消耗的最后一件事是将动态输出渲染到我们的用户界面上。
下面的代码块显示了如何在移动屏幕上消耗数据。
// username
Text(followers[index].login,style:TextStyle(fontSize: 20, fontWeight: FontWeight.w500, color: Colors.grey[700]),)
// User avartar
child: CircleAvatar(backgroundImage: NetworkImage(followers[index].avatarUrl),),
// User location
Text(followers[index].location, style: TextStyle(color: Colors.blue, fontWeight: FontWeight.w700),)
结论
在这篇文章中,我们学习了如何从RESTful API中获取和消费数据,以GitHub的REST API为例。总结一下。
- 我们从GitHub的API中获取了一个用户并显示了他的关注者。
- 我们使用Quicktype从JSON中自动生成dart类。
- 我们在构建一个实际的应用程序时实现了Flutter文件夹组织。