前言
我们在开发中,会面临要从服务器请求数据,然后解析服务器过来的json数据,这个在android中,都有相应的的封装好的很好的插件可以做这样的事情,请求数据有okHttp
,解析有GSON
。那么在flutter中呢,对应的可以是什么呢,我目前请求数据使用的是dio
,解析使用的是json_serializable
,下面是一个简单的例子
实践
一、集成插件
在pubspec.yaml
文件中添加dio
和json_serializable
的相关插件,这里我贴上我的:
dependencies:
flutter:
sdk: flutter
dio: ^3.0.8 #网络请求
json_annotation: ^3.0.1
dev_dependencies:
flutter_test:
sdk: flutter
#这两个是dev的,不要放到上面去了哦
build_runner: ^1.7.3
json_serializable: ^3.2.5
二、封装网络请求
import 'package:dio/dio.dart';
import 'dart:convert';
import 'package:the_first_one/model/Api.dart';
//要查网络请求的日志可以使用过滤<net>
class NetUtil {
static const String GET = "get";
static const String POST = "post";
//get请求
static void get(String url, Function callBack,
{Map<String, String> params, Function errorCallBack}) async {
_request(Api.BaseUrl + url, callBack,
method: GET, params: params, errorCallBack: errorCallBack);
}
//post请求
static void post(String url, Function callBack,
{Map<String, String> params, Function errorCallBack}) async {
_request(url, callBack,
method: POST, params: params, errorCallBack: errorCallBack);
}
//具体的还是要看返回数据的基本结构
//公共代码部分
static void _request(String url, Function callBack,
{String method,
Map<String, String> params,
Function errorCallBack}) async {
print("<net> url :<" + method + ">" + url);
if (params != null && params.isNotEmpty) {
print("<net> params :" + params.toString());
}
String errorMsg = "";
int statusCode;
try {
Response response;
if (method == GET) {
//组合GET请求的参数
if (params != null && params.isNotEmpty) {
StringBuffer sb = new StringBuffer("?");
params.forEach((key, value) {
sb.write("$key" + "=" + "$value" + "&");
});
String paramStr = sb.toString();
paramStr = paramStr.substring(0, paramStr.length - 1);
url += paramStr;
}
response = await Dio().get(url);
} else {
if (params != null && params.isNotEmpty) {
response = await Dio().post(url, data: params);
} else {
response = await Dio().post(url);
}
}
statusCode = response.statusCode;
//处理错误部分
if (statusCode < 0) {
errorMsg = "网络请求错误,状态码:" + statusCode.toString();
_handError(errorCallBack, errorMsg);
return;
}
if (callBack != null) {
callBack(response.data["data"]);
print("<net> response data:" + response.data["data"]);
}
} catch (exception) {
_handError(errorCallBack, exception.toString());
}
}
//处理异常
static void _handError(Function errorCallback, String errorMsg) {
if (errorCallback != null) {
errorCallback(errorMsg);
}
print("<net> errorMsg :" + errorMsg);
}
}
以上的封装,主要基于返回的数据结构,我造了个数据,大概长下面这样:
在这里,我使用mocky来创建API
{
"statusCode": 1,
"data": {
"name": "zoe",
"email": "zoey@qq.com",
"pics": [
"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1534747043&di=2e3d49c934bb603bcf3f2fe8befd94fc&imgtype=jpg&er=1&src=http%3A%2F%2Fimg0.pconline.com.cn%2Fpconline%2F1309%2F30%2F3571757_9.jpg",
"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1534152325030&di=d1d8493bfe1d5f7a9715b6db8ef3d29d&imgtype=0&src=http%3A%2F%2Fc1.cdn.goumin.com%2Fcms%2Fdetail%2Fday_171101%2F20171101_140dd79.png",
"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1534152325029&di=684aa3a8225a7828ba6b04c8ea4bccd3&imgtype=0&src=http%3A%2F%2Fimgq.duitang.com%2Fuploads%2Fblog%2F201505%2F15%2F20150515014759_Qz5Tw.thumb.700_0.jpeg"
]
}
}
三、创建model
为了便利的使用json_serializable
库,我们使用这位大牛的这个小工具:
将右侧框内转换过的内容复制下来,在自己项目中创建user.dart文件,将你复制的内容粘贴进去。然后你会看到类中一些地方会飘红线,这是正常的哈,执行下面的命令后就会好了:
这个时候,你在项目根目录下输入命令:flutter packages pub run build_runner build
(这个命令需要每次在model类中进行更改时都要手动运行构建。也可以使用命令:flutter packages pub run build_runner watch
,它会监视我们项目中文件的变化,并在需要时自动构建必要的文件,只需启动一次观察器,然后并让它在后台运行,这是安全的。个人推荐后面这个命令哈),完成之后会在user.dart
同级目录下,自动创建一个名为user.g.dart
的文件:
有时候也会有些很诡异的事情出现,比如不管怎么输命令,最后就是生成不了g.dart文件,这时候可以使用命令flutter packages pub run build_runner build --delete-conflicting-outputs
,将所有的都删除,重新生成,一般都会变好,我也是不晓得为什么
以下是日志(其中会有一些警告信息,比如Unable to resolve asset ID for "dart:ui"
,在我看来,好像不影响哈,暂时可以不用管):
F:\FlutterSpace\flutter_the_first_demo>flutter packages pub run build_runner build
[INFO] Generating build script...
[INFO] Generating build script completed, took 465ms
[INFO] Initializing inputs
[INFO] Reading cached asset graph...
[WARNING] Throwing away cached asset graph due to version mismatch.
[INFO] Reading cached asset graph completed, took 57ms
[INFO] Building new asset graph...
[INFO] Building new asset graph completed, took 522ms
[INFO] Checking for unexpected pre-existing outputs....
[INFO] Checking for unexpected pre-existing outputs. completed, took 2ms
[INFO] Running build...
[INFO] 2.6s elapsed, 3/65 actions completed.
[INFO] 3.6s elapsed, 4/65 actions completed.
[INFO] 4.7s elapsed, 4/65 actions completed.
[INFO] 5.7s elapsed, 4/65 actions completed.
[INFO] 6.8s elapsed, 4/65 actions completed.
[INFO] 7.9s elapsed, 4/65 actions completed.
[INFO] 9.0s elapsed, 4/65 actions completed.
[INFO] 10.0s elapsed, 4/65 actions completed.
[SEVERE] json_serializable on lib/components/BottomComponent2.dart:
Unable to resolve asset ID for "dart:ui"
[INFO] 17.0s elapsed, 56/65 actions completed.
[INFO] Running build completed, took 17.7s
[INFO] Caching finalized dependency graph...
[INFO] Caching finalized dependency graph completed, took 52ms
[SEVERE] Failed after 17.8s
pub finished with exit code 1
使用
import 'package:flutter/material.dart';
import 'package:the_first_one/model/user.dart';
import 'package:the_first_one/utils/NetUtil.dart';
import 'package:the_first_one/components/LoadingComponent.dart';
class JsonSeralizablePage extends StatefulWidget {
@override
_JsonSeralizablePageState createState() => _JsonSeralizablePageState();
}
class _JsonSeralizablePageState extends State<JsonSeralizablePage> {
String name = "";
String email = "";
List<String> picList = <String>[];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("JSON"),
),
body: (picList != null && picList.length == 0)
? LoadingComponent()
: SingleChildScrollView(
child: Column(
children: <Widget>[
Text(
name,
style: TextStyle(color: Colors.black, fontSize: 20.0),
),
SizedBox(height: 20.0),
Text(
email,
style: TextStyle(color: Colors.black, fontSize: 15.0),
),
SizedBox(height: 20.0),
SizedBox(
height: 250.0 * picList.length,
child: ListView.builder(
physics: ClampingScrollPhysics(),
itemCount: picList != null && picList.length > 0
? picList.length
: 0,
itemBuilder: (BuildContext context, int index) {
return picList != null && picList.length > 0
? Image(
image: NetworkImage(picList[index]),
width: 400.0,
height: 250.0,
fit: BoxFit.cover)
: Text("no pics");
},
),
),
],
),
),
);
}
@override
void initState() {
super.initState();
getContent();
}
//获取网络数据
void getContent() {
NetUtil.get("http://www.mocky.io/v2/5b7143ae3200001402f36c46", (data) {
User user = User.fromJson(data);
setState(() {
name = user.name;
email = user.email;
picList = user.pics;
});
}, errorCallBack: (errorMsg) {
print("error:" + errorMsg);
});
}
}
效果:
写在最后
本人刚入门,所学尚浅,如有不当或不足之处,希望能得到指点