在这个内容为王的时代,数据涞源一般都会来源于网络,所以一款app,现在都离不开要通过网络来获取数据,对于客户端来说,获取网络数据就需要在客户端集成网络请求,Flutter官方为我们提供了HttpClient来发起网络请求,可以参考在Flutter中发起HTTP网络请求
虽然Flutter官网提供了自己的网络请求,但是官方还有一句话,是说HttpClient本身功能较弱,很多常用功能都不支持,所以官方建议我们使用dio来发起网络请求,这是一个强大易用的dart http 请求库,支持Restful API、FormData、拦截器、请求取消、Cookie管理、文件上传/下载、全局配置、超时等
这篇文章还是在上一篇文章Flutter 学习- 基础框架的基础上继续完善的,有图有真相,下面先看效果图
项目列表的展示主要是listview,这部分内容会在后面的文章中分享出来,本篇文章我们主要描述如何在flutter中使用网络请求,并且将数据解析出来
这里我们要先将dio库添加到我们的项目中,我们要打开pubspec.yaml文件,在dependencies:下添加代码
dio: ^2.1.0
在你需要用到dio的地方导入包
import 'package:dio/dio.dart';
官方给出了简单的使用方法
void getHttp() async {
try {
Response response = await Dio().get("http://www.google.com");
print(response);
} catch (e) {
print(e);
}
}
看到了吧其实很简单,dio帮我们完成了所有的操作,我们只要一行代码就得到了我们的请求,但是,当然有但是,我们的日常开发中的接口还会带参数,那要怎么传递呢,官方也给出了简单的使用方法
- 方法1
Response response; Dio dio = new Dio(); response = await dio.get("/test?id=12&name=wendu") print(response.data.toString());
- 方法2
Response response; Dio dio = new Dio(); response = await dio.get("/test", queryParameters: {"id": 12, "name": "wendu"}); print(response.data.toString());
到此dio的使用方法就结束了,这也太简单了,但是这也太不实用了,每次都要把参数那么艰难的拼进去多麻烦,实际开发中使用太不方便了,因此我们就要对这些使用方法进行封装
设置请求,这里我们只做最常用的Get和Post的请求,有兴趣的可以做更深入的探究
static void _request(String url, Function successCallback,
{String method,
Map params,
Function errorCallBack}) async {
print("url = $url");
String errorMsg = "";
int statusCode;
try {
Response response;
BaseOptions baseOptions = new BaseOptions(
connectTimeout: HttpUtils.TIMEOUT_CONNECT,
receiveTimeout: HttpUtils.TIMEOUT_RECEIVE,
);
// dio库中默认将请求数据序列化为json,此处可根据后台情况自行修改
// contentType:new ContentType('application', 'x-www-form-urlencoded',charset: 'utf-8')
Options options = new Options(
connectTimeout: HttpUtils.TIMEOUT_CONNECT,
receiveTimeout: HttpUtils.TIMEOUT_RECEIVE,
sendTimeout: HttpUtils.TIMEOUT_SEND,
);
Dio dio = new Dio(baseOptions);
if (method == HttpUtils.GET) {
response =
await dio.get(url, queryParameters: params, options: options);
} else {
response =
await dio.post(url, queryParameters: params, options: options);
}
statusCode = response.statusCode;
if (statusCode != HttpStatus.ok) {
errorMsg = "网络请求错误,状态码:" + statusCode.toString();
_handError(errorCallBack, errorMsg);
} else {
if (successCallback != null) {
var data = json.decode(response.toString()); //对数据进行Json转化
successCallback(data);
print("data = " + data);
}
}
} catch (exception) {
_handError(errorCallBack, exception.toString());
}
}
方法调用,参数传递
/**
* get 请求
*/
static getData(String url, Function successCallback,
{Map params, Function errorCallBack}) async {
if (params != null && params.isNotEmpty) {
StringBuffer stringBuffer = new StringBuffer("?");
params.forEach((key, value) {
stringBuffer.write("$key" + "=" + "$value" + "&");
});
String paramStr = stringBuffer.toString();
paramStr = paramStr.substring(0, paramStr.length - 1);
url += paramStr;
}
_request(url, successCallback,
method: HttpUtils.GET, params: params, errorCallBack: errorCallBack);
}
/**
* Post请求
*/
static postData(String url, Function successCallback,
{Map params, Function errorCallBack}) async {
_request(url, successCallback,
method: HttpUtils.POST, params: params, errorCallBack: errorCallBack);
}
这时候我们就可以把这些方法放到一个类里面,在后面的请求中直接调用了
HttpController.getData(url, (data) {
if (!mounted) return;
setState(() {
/**
TODO Sth
解析数据,刷新界面
**/
});
}, params: params);
是不是蛮简单,网络请求到此告一段落~~~
网络请求已经完成数据我们拿到了,但是我们怎么搞定数据的解析转变成我们想要的类呢,Android中有Gson帮我们,在flutter中有没有类似的框架呢,恭喜你,flutter中没有,是不是很意外,flutter就是这么的刚,但是呢我们解析也不是不能做,当然是需要我们自己动手的
{
"data": {
"curPage": 1,
"datas": [{
"author": "guojun_fire",
"chapterName": "基础知识",
"link": "https://juejin.im/post/5c9c2c76f265da60c576fab1",
"niceDate": "1天前",
"superChapterName": "自定义控件",
"tags": [
{
"name": "项目",
"url": "/project/list/1?cid=294"
}
],
"title": "你需要了解下Android View的更新requestLayout与重绘invalidate",
},
{
...
},
....
],
"offset": 0,
"over": false,
"pageCount": 314,
"size": 20,
"total": 6265
},
"errorCode": 0,
"errorMsg": ""
}
这个json数据中我们可以看到首先是我们需要一个实体类来接收这个数据中的所有字段
class ArticleBean {
int curPage;
int offset;
bool over;
int pageCount;
int size;
int total;
List datas =[];
}
另外我们看到数据中还有两个json数组,那我们也要对应创建两个数组中数据中的实体类
class Article {
final String author;
final String chapterName;
final String title;
final String niceDate;
final String superChapterName;
final String link;
final List tags;
}
class Tag{
String name;
String url;
}
下面问题来了对于数组,我们要怎么解析呢,直接看示例
class Tag{
String name;
String url;
Tag({this.name, this.url});//创建构造函数
//将我们的实体类数据传入进行解析
factory Tag.fromJson(Map parsedJson){
return Tag(
name: parsedJson['name'],
url: parsedJson['url']
);
}
}
看到Tag类的方法,我们就可以联想到Article类的方法了,是一样的,只是稍做修改
class Article {
final String author;
final String chapterName;
final String title;
final String niceDate;
final String superChapterName;
final String link;
final List tags;
Article(
{this.author,
this.chapterName,
this.title,
this.niceDate,
this.superChapterName,
this.link,
this.tags});
factory Article.fromJson(Map parsedJson) {
return Article(
author: parsedJson['author'],
chapterName: parsedJson['chapterName'],
title: parsedJson['title'],
niceDate: parsedJson['niceDate'],
superChapterName: parsedJson['superChapterName'],
link: parsedJson['link'],
tags: (parsedJson['tags'] as List)
.map((i) => Tag.fromJson(i))
.toList(),);
}
}
重点来看tags的获取,首先是将“tags“这个key的数据进行转化,然后用map进行循环遍历,通过Tag.fromJson方法生成Tag类,最后用tolist方法转化成列表。
parsedJson['tags'] as List)
.map((i) => Tag.fromJson(i))
.toList()
这段代码我们可以拆解来看
var list = parsedJson['tags'] as List;
List tags = new List();
tags = list.map((i) => Tag.fromJson(i)).toList();
这样就容易理解了。
同样的方法我们可以得到ArticleBean类的数据获得
class ArticleBean {
int curPage;
int offset;
bool over;
int pageCount;
int size;
int total;
List datas =[];
ArticleBean(
{this.curPage,
this.offset,
this.over,
this.pageCount,
this.size,
this.total,
this.datas});
factory ArticleBean.from(Map parsedJson) {
return ArticleBean(
curPage: parsedJson["curPage"],
offset: parsedJson["offset"],
over: parsedJson["over"],
pageCount: parsedJson["pageCount"],
size: parsedJson["size"],
total: parsedJson["total"],
datas: (parsedJson['datas'] as List)
.map((i) => Article.fromJson(i))
.toList(),
);
}
}
然后在使用的时候我们只需要把上面的那段json数据传进去就可以解析了
HttpController.getData(url, (data) {
if (!mounted) return;
setState(() {
//data["data"]就是从网络上获取到的数据
ArticleBean articleBean = ArticleBean.from(data["data"]);
});
}, params: params);
到此为止,网络请求和数据解析部分就讲解完成了,后面就可以在各个页面中完成项目中所需要的UI,该项目已被放在Github上面进行开源,内容在不断更新中,后续还会有更多实际项目中所要用到的基础知识,如有问题,也欢迎大家留言,指正。