Flutter实现网络请求的方法示例
flutter网络请求使用的是dio。dio是一个强大易用的dart http请求库,支持restful api、formdata、拦截器、请求取消、cookie管理、文件上传/下载.......
flutter json数据解析是使用了json_serializable package包。它是一个自动化源代码生成器,可以为我们生成json序列化模板。由于序列化代码不再由我们手写和维护,我们将运行时产生json序列化异常的风险降至最低。
flutter网络请求数据并且展示效果图:
数据接口
数据是使用的聚合数据的api,影讯api合集,大家可以注册个账号,申请使用一下,像这样
添加依赖
在pubspec.yaml文件中添加所需要的第三方依赖库
environment: sdk: ">=2.1.0 <3.0.0" dependencies: flutter: sdk: flutter json_annotation: ^2.0.0 connectivity: ^0.4.2 dio: ^2.0.15 event_bus: ^1.0.3 # the following adds the cupertino icons font to your application. # use with the cupertinoicons class for ios style icons. cupertino_icons: ^0.1.2 dev_dependencies: flutter_test: sdk: flutter
网络请求过程分析
static netfetch(url,params,map<string,string> header,options option,{notip = false}) async { //获取网络的连接状态,如果没有连接网络,返回network_error var connectivityresult = await (new connectivity().checkconnectivity()); if(connectivityresult == connectivityresult.none) { return new resultdata(code.errorhandlefunction(code.network_error, "", notip),false,code.network_error); } //请求头存放集合 map<string,string> headers = new hashmap(); if(header != null) { headers.addall(header); } //option存放请求的一些配置信息 if(option != null) { option.headers = headers; }else { //get请求 option = new options(method:'get'); option.headers = headers; } //超时时间15000ms option.connecttimeout = 15000; //创建dio对象 dio dio = new dio(); response response; try{ //执行网络请求,await和async配合使用,表示这是一个异步耗时操作 //执行结果不会立马返回。 response = await dio.request(url,data: params,options: option); }on dioerror catch(e) { //异常处理 .... return new resultdata(code.errorhandlefunction(errorresponse.statuscode, e.message, notip), false, errorresponse.statuscode); } try{ if(response.statuscode == 200 || response.statuscode == 201) { //网络请求成功 return await new resultdata(response.data, true, code.success,headers: response.headers); } }catch(e) { //异常处理 print('返回参数' + e.tostring() + url); return new resultdata(response.data, false, response.statuscode,headers: response.headers); } return new resultdata(code.errorhandlefunction(response.statuscode, "", notip), false, response.statuscode); }
这个是最底层类封装了一个静态的请求方法,直接调用dio的request方法进行网路请求,很简单。
//如果这个是耗时方法,就会用async标记,耗时操作用await标记,表示是一个异步操作。 static gettodayfilmlistdao() async { //获取请求的url string url = address.gettodayfilmlist(); //调用上面封装的网络请求方法进行网络请求 var res = await httpmanager.netfetch(url, null, null, null); if(res != null && res.result) { var data = res.data; if(data == null || data.length == 0) { return await new dataresult([],true); } //网络请求成功,进行数据解析 var response = todayfilmresponse.fromjson(data); //返回数据 return await new dataresult(response.result,true); }else { return await new dataresult(null,false); } }
获取url方法很简单,就是字符串拼接了一下
static gettodayfilmlist() { return "${host}movie/movies.today?cityid=1&dtype=&key=713a408e855352d913806ef1e3ce3c33"; }
下面分析一下json数据解析过程。
如上所说,json解析使用的是json_serializable package包。它是一个自动化源代码生成器,可以为我们生成json序列化模板。
网络请求获取到的json数据是这样的
{ "movieid":"135808", "moviename":"新喜剧之王", "pic_url":"http:\/\/img5.mtime.cn\/mt\/2019\/02\/02\/113216.53857992_182x243x4.jpg" }, todayfilmbean类 //todayfilmbean.g.dart将在我们运行生成命令之后自动生成 part 'todayfilmbean.g.dart'; //这个标注是告诉生成器,这个类是要生成的model类 @jsonserializable() class todayfilmbean{ string movieid; string moviename; string pic_url; //构造函数 todayfilmbean(this.movieid,this.moviename,this.pic_url); //json转换为bean对象 factory todayfilmbean.fromjson(map<string,dynamic> json) => _$todayfilmbeanfromjson(json); //bean对象转换为json map<string,dynamic> tojson() => _$todayfilmbeantojson(this); } 生成的todayfilmbean.g.dart类是这样的 part of 'todayfilmbean.dart'; //json转换为bean对象 todayfilmbean _$todayfilmbeanfromjson(map<string,dynamic> json) { return todayfilmbean(json['movieid'] as string,json['moviename'] as string, json['pic_url'] as string); } //bean对象转换为json map<string,dynamic> _$todayfilmbeantojson(todayfilmbean instance) => <string,dynamic> { 'movieid': instance.movieid, 'moviename': instance.moviename, 'pic_url':instance.pic_url };
有两种运行代码生成器的方法:
1.一次性生成
通过在我们的项目根目录下运行flutter packages pub run build_runner build,我们可以在需要时为我们的model生成json序列化代码。这触发了一次性构建,它通过我们的源文件,挑选相关的并为它们生成必要的序列化代码。
虽然这非常方便,但如果我们不需要每次在model类中进行更改时都要手动运行构建命令的话会更好。
2.持续生成
使用_watcher_可以使我们的源代码生成的过程更加方便。它会监视我们项目中文件的变化,并且在需要时自动构建必要的文件。我们可以通过flutter packages pub run build_runner watch 在项目根目录下运行来启动_watcher_。
只需启动一次观察器,然后并让它在后台运行,这是安全的。
执行序列化只需执行
//把json数据转化为了bean对象 var filmbean = todayfilmbean.fromjson(json);
使用gridview最终展示结果
dataresult dataresult; list<todayfilmbean> mdata = []; //当statefulwiget被嵌入此view树中,就会为此widget创建state对象 //当state对象被创建了,framework就会调用initstate()方法 @override void initstate() { //初始化数据 gettodayfilm(); super.initstate(); } void gettodayfilm() async { //这是一个异步操作,结果返回有一定延迟 dataresult = await todaydao.gettodayfilmlistdao(); //调用setstate方法会通知framework控件状态有变化,它会立马触发 //state的build方法更新widget状态 setstate(() { mdata = dataresult.data; }); }
上面是初始化网络请求,在请求到数据后,调用setstate刷新ui
//state的build方法,调用setstate方法后,此方法就会被触发 //用来刷新ui @override widget build(buildcontext context) { return scaffold( appbar: appbar( title: text(widget.title), ), //如果mdata.length == 0,展示一个loading框,否则展示数据 body: mdata.length == 0 ? new center(child: new circularprogressindicator()): //创建gridview对象 new gridview.builder( griddelegate: slivergriddelegatewithfixedcrossaxiscount( crossaxiscount: 3, //每行2个 mainaxisspacing: 1.0, //主轴(竖直)方向间距 crossaxisspacing: 1.0, //纵轴(水平)方向间距 childaspectratio: 0.7 //纵轴缩放比例 ), //item数量 itemcount:mdata.length, //创建每个item itembuilder: (buildcontext context,int index) { return _getwidget(index); }), ); } _getwidget(int index) { //添加要展示的item内容 return new column( children: <widget>[ new expanded(child: new carditem(color: colors.black12,child: _getchild(index)),flex: 8,), //显示网络请求文本 new expanded(child: new text(mdata[index].moviename, textalign: textalign.end, maxlines: 1, ), flex:1) ]); } _getchild(int i) { return new padding(padding: new edgeinsets.all(1.0), //显示网络请求的图片 child: new image(image: networkimage(mdata[i].pic_url))); }
一个自定义的carditem
class carditem extends statelesswidget{ final widget child; final edgeinsets margin; final color color; final roundedrectangleborder shape; final double elevation; carditem({@required this.color,this.child,this.elevation = 5.0,this.shape,this.margin}); @override widget build(buildcontext context) { edgeinsets margin = this.margin; roundedrectangleborder shape = this.shape; color color = this.color; margin ??= edgeinsets.only(left: 2.0,top: 2.0,right: 2.0,bottom: 2.0); shape ??= new roundedrectangleborder(borderradius: new borderradius.all(radius.circular(4.0))); color ??= new color(0xffeeff); return new card(elevation: elevation,shape: shape,color: color,margin: margin,child: child,); } }
好了,flutter网络请求并且展示数据就这样实现的。
最后附上demo地址:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
下一篇: 晚上散步