前言
在這個內(nèi)容為王的時代赃阀,數(shù)據(jù)淶源一般都會來源于網(wǎng)絡(luò)霎肯,所以一款app,現(xiàn)在都離不開要通過網(wǎng)絡(luò)來獲取數(shù)據(jù)榛斯,對于客戶端來說观游,獲取網(wǎng)絡(luò)數(shù)據(jù)就需要在客戶端集成網(wǎng)絡(luò)請求,F(xiàn)lutter官方為我們提供了HttpClient來發(fā)起網(wǎng)絡(luò)請求驮俗,可以參考在Flutter中發(fā)起HTTP網(wǎng)絡(luò)請求
轉(zhuǎn)折
雖然Flutter官網(wǎng)提供了自己的網(wǎng)絡(luò)請求懂缕,但是官方還有一句話,是說HttpClient本身功能較弱王凑,很多常用功能都不支持搪柑,所以官方建議我們使用dio來發(fā)起網(wǎng)絡(luò)請求,這是一個強(qiáng)大易用的dart http 請求庫索烹,支持Restful API工碾、FormData、攔截器百姓、請求取消渊额、Cookie管理、文件上傳/下載、全局配置旬迹、超時等
正文 - 網(wǎng)絡(luò)請求
這篇文章還是在上一篇文章Flutter 學(xué)習(xí)- 基礎(chǔ)框架的基礎(chǔ)上繼續(xù)完善的火惊,有圖有真相,下面先看效果圖
項目列表的展示主要是listview奔垦,這部分內(nèi)容會在后面的文章中分享出來屹耐,本篇文章我們主要描述如何在flutter中使用網(wǎng)絡(luò)請求,并且將數(shù)據(jù)解析出來
- 引入第三方框架
這里我們要先將dio庫添加到我們的項目中椿猎,我們要打開pubspec.yaml文件,在dependencies:下添加代碼
dio: ^2.1.0
在你需要用到dio的地方導(dǎo)入包
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幫我們完成了所有的操作,我們只要一行代碼就得到了我們的請求犯眠,但是俗他,當(dāng)然有但是,我們的日常開發(fā)中的接口還會帶參數(shù)阔逼,那要怎么傳遞呢,官方也給出了簡單的使用方法地沮,
- 方法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的使用方法就結(jié)束了嗜浮,這也太簡單了,但是這也太不實用了摩疑,每次都要把參數(shù)那么艱難的拼進(jìn)去多麻煩危融,實際開發(fā)中使用太不方便了,因此我們就要對這些使用方法進(jìn)行封裝
- 封裝 - 第一步
設(shè)置請求雷袋,這里我們只做最常用的Get和Post的請求吉殃,有興趣的可以做更深入的探究
static void _request(String url, Function successCallback,
{String method,
Map<String, String> 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庫中默認(rèn)將請求數(shù)據(jù)序列化為json,此處可根據(jù)后臺情況自行修改
// 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 = "網(wǎng)絡(luò)請求錯誤,狀態(tài)碼:" + statusCode.toString();
_handError(errorCallBack, errorMsg);
} else {
if (successCallback != null) {
var data = json.decode(response.toString()); //對數(shù)據(jù)進(jìn)行Json轉(zhuǎn)化
successCallback(data);
print("data = " + data);
}
}
} catch (exception) {
_handError(errorCallBack, exception.toString());
}
}
- 封裝-第二步
方法調(diào)用楷怒,參數(shù)傳遞
/**
* get 請求
*/
static getData(String url, Function successCallback,
{Map<String, String> 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<String, String> params, Function errorCallBack}) async {
_request(url, successCallback,
method: HttpUtils.POST, params: params, errorCallBack: errorCallBack);
}
這時候我們就可以把這些方法放到一個類里面蛋勺,在后面的請求中直接調(diào)用了
HttpController.getData(url, (data) {
if (!mounted) return;
setState(() {
/**
TODO Sth
解析數(shù)據(jù),刷新界面
**/
});
}, params: params);
是不是蠻簡單鸠删,網(wǎng)絡(luò)請求到此告一段落~~~
正文- 數(shù)據(jù)解析
網(wǎng)絡(luò)請求已經(jīng)完成數(shù)據(jù)我們拿到了抱完,但是我們怎么搞定數(shù)據(jù)的解析轉(zhuǎn)變成我們想要的類呢,Android中有Gson幫我們刃泡,在flutter中有沒有類似的框架呢巧娱,恭喜你,flutter中沒有烘贴,是不是很意外禁添,flutter就是這么的剛,但是呢我們解析也不是不能做桨踪,當(dāng)然是需要我們自己動手的
- 首先先看一個接口數(shù)據(jù)
{
"data": {
"curPage": 1,
"datas": [{
"author": "guojun_fire",
"chapterName": "基礎(chǔ)知識",
"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數(shù)據(jù)中我們可以看到首先是我們需要一個實體類來接收這個數(shù)據(jù)中的所有字段
class ArticleBean {
int curPage;
int offset;
bool over;
int pageCount;
int size;
int total;
List<Article> datas =[];
}
另外我們看到數(shù)據(jù)中還有兩個json數(shù)組老翘,那我們也要對應(yīng)創(chuàng)建兩個數(shù)組中數(shù)據(jù)中的實體類
class Article {
final String author;
final String chapterName;
final String title;
final String niceDate;
final String superChapterName;
final String link;
final List<Tag> tags;
}
class Tag{
String name;
String url;
}
下面問題來了對于數(shù)組,我們要怎么解析呢,直接看示例
class Tag{
String name;
String url;
Tag({this.name, this.url});//創(chuàng)建構(gòu)造函數(shù)
//將我們的實體類數(shù)據(jù)傳入進(jìn)行解析
factory Tag.fromJson(Map<String, dynamic> parsedJson){
return Tag(
name: parsedJson['name'],
url: parsedJson['url']
);
}
}
看到Tag類的方法酪捡,我們就可以聯(lián)想到Article類的方法了叁征,是一樣的,只是稍做修改
class Article {
final String author;
final String chapterName;
final String title;
final String niceDate;
final String superChapterName;
final String link;
final List<Tag> tags;
Article(
{this.author,
this.chapterName,
this.title,
this.niceDate,
this.superChapterName,
this.link,
this.tags});
factory Article.fromJson(Map<String, dynamic> 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(),);
}
}
重點(diǎn)來看tags的獲取逛薇,首先是將“tags“這個key的數(shù)據(jù)進(jìn)行轉(zhuǎn)化捺疼,然后用map進(jìn)行循環(huán)遍歷,通過Tag.fromJson方法生成Tag類永罚,最后用tolist方法轉(zhuǎn)化成列表啤呼。
parsedJson['tags'] as List)
.map((i) => Tag.fromJson(i))
.toList()
這段代碼我們可以拆解來看
var list = parsedJson['tags'] as List;
List<Tag> tags = new List();
tags = list.map((i) => Tag.fromJson(i)).toList();
這樣就容易理解了。
同樣的方法我們可以得到ArticleBean類的數(shù)據(jù)獲得
class ArticleBean {
int curPage;
int offset;
bool over;
int pageCount;
int size;
int total;
List<Article> datas =[];
ArticleBean(
{this.curPage,
this.offset,
this.over,
this.pageCount,
this.size,
this.total,
this.datas});
factory ArticleBean.from(Map<String, dynamic> 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數(shù)據(jù)傳進(jìn)去就可以解析了
HttpController.getData(url, (data) {
if (!mounted) return;
setState(() {
//data["data"]就是從網(wǎng)絡(luò)上獲取到的數(shù)據(jù)
ArticleBean articleBean = ArticleBean.from(data["data"]);
});
}, params: params);
到此為止呢袱,網(wǎng)絡(luò)請求和數(shù)據(jù)解析部分就講解完成了官扣,后面就可以在各個頁面中完成項目中所需要的UI,該項目已被放在Github上面進(jìn)行開源,內(nèi)容在不斷更新中羞福,后續(xù)還會有更多實際項目中所要用到的基礎(chǔ)知識惕蹄,如有問題,也歡迎大家留言治专,指正卖陵。
- Github 開源地址 Flutter_Wheel
以下是我的Flutter系列的鏈接,后續(xù)會持續(xù)更新张峰,歡迎大家指正泪蔫。
Flutter 系列文章
- Flutter 學(xué)習(xí) - 開篇
- Flutter 學(xué)習(xí) - 基礎(chǔ)框架
- Flutter 學(xué)習(xí) - 網(wǎng)絡(luò)請求和數(shù)據(jù)解析
- Flutter 學(xué)習(xí) - Widget 之 Text
- Flutter 學(xué)習(xí) - Widget 之 RichText
- Flutter 學(xué)習(xí) - Widget 之 Image和Icon
- Flutter 學(xué)習(xí) - Widget 之 TextField
- Flutter 學(xué)習(xí) - Widget 之 菜單按鈕
- Flutter 學(xué)習(xí) - Widget 之 布局 Widget
- Flutter 學(xué)習(xí) - 容器類Widget
- Flutter 學(xué)習(xí) - 可滾動的 Widget
- Flutter 學(xué)習(xí) - 功能類Widget