45fan.com - 路饭网

搜索: 您的位置主页 > 手机频道 > 阅读资讯:Flutter实现网络请求

Flutter实现网络请求

2019-03-30 18:00:45 来源:www.45fan.com 【
  • Flutter网络请求使用的是Dio。Dio是一个强大易用的dart http请求库,支持Restful API、FormData、拦截器、请求取消、Cookie管理、文件上传/下载…

  • Flutter json数据解析是使用了json_serializable package包。它是一个自动化源代码生成器,可以为我们生成JSON序列化模板。由于序列化代码不再由我们手写和维护,我们将运行时产生JSON序列化异常的风险降至最低。

  • Flutter网络请求数据并且展示效果图:
    Flutter实现网络请求

  • 数据接口
    数据是使用的聚合数据的API,影讯API合集,大家可以注册个账号,申请使用一下,像这样
    Flutter实现网络请求

  • 添加依赖
    在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地址:https://github.com/xinhuashi/flutter_http_demo.git

 
 

本文地址:http://www.45fan.com/a/luyou/100056.html
Tags: 实现 网络 flutter
编辑:路饭网
关于我们 | 联系我们 | 友情链接 | 网站地图 | Sitemap | App | 返回顶部