Dio网络封装以及数据转模型

一、为什么需要封装Dio

1、迁移代码

当组件库中的方法发生改变,需要迁移的时候,如果有多处地方用到,那么需要对使用到的每个文件都进行修改,非常的繁琐而且很容易出问题。

2、请求库切换

当不需要Dio库的时候,我们可以试随时方便切换到别的网络库。

3、统一配置

因为一个应用程序基本都是统一的配置方式,所以我们可以针对拦截器 、转换器 、 缓存 、统一处理错误 、代理配置、证书校验 等多个配置进行统一管理。

二、使用单利模式进行Dio封装

1、为什么使用单例模式?

每个页面都会在进行网络请求,如果每次都要初始化一个dio,那么会增加系统不必要的开销,而使用单例模式对象一旦创建每次都是访问同一个对象,不会再实例化对象。

2、创建单例类
import 'package:dio/dio.dart';
class HttpRequest {
  static final BaseOptions options = BaseOptions(baseUrl: "");

  static final Dio dio = Dio(options);

  static Future<T> request<T>(String url,
      {String method, Map<String, dynamic> params, Interceptor inter}) async {
    // 1.请求的单独配置
    Options options = Options(method: method);
    options.headers = httpHeaders;
//    // 2.添加第一个拦截器
//    Interceptor dInter =
//        InterceptorsWrapper(onRequest: (RequestOptions options) {
//      // 1.在进行任何网络请求的时候, 可以添加一个loading显示
//
//      // 2.很多页面的访问必须要求携带Token,那么就可以在这里判断是有Token
//
//      // 3.对参数进行一些处理,比如序列化处理等
//      print("拦截了请求");
//      return options;
//    }, onResponse: (Response response) {
//      print("拦截了响应");
//      return response;
//    }, onError: (DioError error) {
//      print("拦截了错误");
//      return error;
//    });
//
//    List<Interceptor> inters = [dInter];
//    if (inter != null) {
//      inters.add(inter);
//    }
//
//    dio.interceptors.addAll(inters);
    // 3.发送网络请求
    try {
      Response response =
          await dio.request(url, data: params, options: options);
      return response.data;
    } on DioError catch (e) {
      return Future.error(e);
    }
  }
}

const httpHeaders = {
  'Content-Type': 'application/json',
  'X-LC-Id': 'a4Cj1Hm5aMrdhob6xGw71B5A-gzGzoHsz',
  'X-LC-Key': 'XQaL1tUQC0DCQxBA9fpoR21C',
};
3、方法调用
   HttpRequest.request(url, method: 'GET').then((res) {
      var list = new GHAddressModel.fromJson(res).results;
      setState(() {
        this._list = list;
      });
    });
/// 收货地址列表
class GHAddressList extends StatefulWidget {
  @override
  _GHAddressListState createState() => _GHAddressListState();
}

class _GHAddressListState extends State<GHAddressList> {
  /// 地址列表
  var _list = [];
  GlobalKey _easyRefreshKey = new GlobalKey();
  _getAddressList() async {
    //addressDetails
    //shopAddress
    var url = "https://a4cj1hm5.api.lncld.net/1.1/classes/shopAddress";
    var c = Uri.encodeComponent('-createdAt');
    var d = Uri.encodeComponent('李');
    url = url + '?' + "order=" + c;

    HttpRequest.request(url, method: 'GET').then((res) {
      var list = new GHAddressModel.fromJson(res).results;
      setState(() {
        this._list = list;
      });
    });
  }

  void initState() {
    super.initState();
    this._easyRefreshKey.currentState;
  }

  void deactivate() {
    // 返回到当前页刷新
    var bool = ModalRoute.of(context).isCurrent;
    if (bool) {
      this._getAddressList();
    }
  }

  Widget ListItem(Results results) {
    return InkWell(
      onTap: () {},
      child: Container(
        margin: EdgeInsets.only(top: 5, bottom: 5),
        width: ScreenAdaper.getScreenWidth(),
        child: Column(
          children: <Widget>[
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: <Widget>[
                Row (
                  children: <Widget>[
                    Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: <Widget>[
                        Container(
                          child: Row(
                            children: <Widget>[
                              Container(
                                width:50,
                                child: Text(
                                  results.name,
                                  overflow: TextOverflow.ellipsis,
                                  style:TextStyle(
                                    fontSize: 18,
                                    fontWeight: FontWeight.bold,
                                  ),
                                ),
                              ),
                              SizedBox(
                                width: 10,
                              ),
                              Container(
                                child: Text(
                                  results.phone,
                                  style: TextStyle(fontSize: 16,fontWeight: FontWeight.bold),
                                ),
                              ),
                            ],
                          ),
                        ),
                        Container(
                          width: ScreenAdaper.getScreenWidth() - 20 - 20 - 30,
                          child: Text(
                            results.province +
                                results.city +
                                results.area +
                                results.detailsAddress,
                            style: TextStyle(fontSize: 14, color: Colors.black54),
                          ),
                        ),
                      ],
                    )
                  ],
                ),
                GestureDetector(

                  onTap: () {
                    Navigator.pushNamed(context, '/GHAddressEdit', arguments: {
                      'name': "${results.name}",
                      'zone': "${results.zone}",
                      'detailsAddress': "${results.detailsAddress}",
                      'phoneNumber': results.phone,
                      'objectId': results.objectId,
                    });
                  },
                  child: Container(
                    child: Icon(
                      Icons.edit,
                      size: 30,
                    ),
                  ),
                ),
              ],
            ),
            Divider(),
          ],
        )
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    ScreenAdaper.init(context);
    return Scaffold(
      appBar: AppBar(
        actions: <Widget>[
          TextButton(
            onPressed: () {
              Navigator.pushNamed(context, '/GHAddressEdit');
            },
            child: Icon(Icons.add),
          )
        ],
        title: Text("地址管理"),
      ),
      body: Container(
          padding: EdgeInsets.all(20),
          child: EasyRefresh(
            firstRefresh: true,
            key:_easyRefreshKey,
            onRefresh: () async {
              await this._getAddressList();
            },
            onLoad: () async {
              await this._getAddressList();
            },
            child: ListView.builder(
              itemBuilder: (context, index) {
                return ListItem(this._list[index]);
              },
              itemCount: this._list.length,
            ),
          )),
    );
  }
}

三、数据转模型

我们当然不能手写来实现,我们使用quickType来进行转化。
数据请求后,转模型

   HttpRequest.request(url, method: 'GET').then((res) {
      var list = new GHAddressModel.fromJson(res).results;
      setState(() {
        this._list = list;
      });
    });

GHAddressModel类型

class GHAddressModel {
  List<Results> results;

  GHAddressModel({this.results});

  GHAddressModel.fromJson(Map<String, dynamic> json) {
    if (json['results'] != null) {
      results = new List<Results>();
      json['results'].forEach((v) {
        results.add(new Results.fromJson(v));
      });
    }
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    if (this.results != null) {
      data['results'] = this.results.map((v) => v.toJson()).toList();
    }
    return data;
  }
}

class Results {
  String province;
  String area;
  String city;
  String detailsAddress;
  String remark;
  String zone;
  String phone;
  String userId;
  String objectId;
  String updatedAt;
  String createdAt;
  String name;
  String isDefault;
  Where where;

  Results(
      {this.detailsAddress,
        this.remark,
  this.province,
  this.area,
  this.city,
        this.zone,
        this.phone,
        this.userId,
        this.objectId,
        this.updatedAt,
        this.createdAt,
        this.name,
        this.isDefault,
        this.where});

  Results.fromJson(Map<String, dynamic> json) {
    detailsAddress = json['detailsAddress'];
    if (detailsAddress == null) {
      detailsAddress = "暂无地址";
    }
    remark = json['remark'];
    zone = json['zone'];
    if (zone == null) {
      zone = "暂无地址";
    }
    phone = json['phone'];
    if (phone == null) {
      phone = "13800000000";
    }
    userId = json['userId'];
    objectId = json['objectId'];
    updatedAt = json['updatedAt'];
    createdAt = json['createdAt'];
    province = json['province'];
    city = json['city'];
    area = json['area'];
    name = json['name'];
    if (name == null) {
      name = "没有设置";
    }
    isDefault = json['isDefault'];
    where = json['where'] != null ? new Where.fromJson(json['where']) : null;
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['detailsAddress'] = this.detailsAddress;
    data['remark'] = this.remark;
    data['zone'] = this.zone;
    data['phone'] = this.phone;
    data['userId'] = this.userId;
    data['objectId'] = this.objectId;
    data['updatedAt'] = this.updatedAt;
    data['createdAt'] = this.createdAt;
    data['name'] = this.name;
    data['isDefault'] = this.isDefault;
    data['province'] = this.province;
    data['city'] = this.city;
    data['area'] = this.area;


    if (this.where != null) {
      data['where'] = this.where.toJson();
    }
    return data;
  }
}

class Where {
  String token;
  String userId;
  Where({this.token, this.userId});
  Where.fromJson(Map<String, dynamic> json) {
    token = json['token'];
    userId = json['userId'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['token'] = this.token;
    data['userId'] = this.userId;
    return data;
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容