Dio网络封装以及数据转模型
2024-04-09 16:15:32  阅读数 7635

一、为什么需要封装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;
  }
}