一:前言 - 什么是反射机制,Flutter为什么禁用反射机制?


在Flutter中它的网络请求和数据解析稍微的比较麻烦一点,因为Flutter不支持反射机制。相信大家都看到这么一条,就是Flutter不支持反射,那首先有一点需要我们明白的。什么是反射?不知道大家看到这个问题的时候,有多少人脑子里面是一下子能闪出反射的概念的,我们首先还是说说,什么是反射机制。

反射机制简单来说就是动态获取类或者对象中的属性,对于任何一个类,我们都能够知道这个类有哪些方法和属性。对于任何一个对象,我们都能够对它的方法和属性进行调用。我们把这种动态获取对象信息和调用对象方法的功能称之为反射机制。要往深了去理解,的确反射机制是一个比较难的概念,这里有一篇写的比较好的 浅谈反射机制 传送门给大家有兴趣的看这篇应该对反射是可以有一个比较深的认知的。

大概知道之后,再说一点就是其实单纯的Dart语言是支持反射机制的,只不过Flutter把它禁止了而已,那我们得追究一下 为什么Flutter要禁止Dart的反射机制呢?

这个问题其实官网给过我们答案,我们看看官方是怎么说的:

      简单的总结一下:由于反射默认会使用所有的代码,就导致在发布应用的时候没法去除掉未使用的代码,没法显著的优化程序的大小,所以Flutter禁用了Dart的反射机制。

二:Flutter的JSON序列化


既然我们在前面说了Flutter不支持反射机制,那它的JSON序列化又是怎样进行的呢?

首先Flutter中基本的JSON序列化是非常简单的,lutter有一个内置dart:convert库,其中包含一个简单的JSON编码器和解码器。但是不管是dart:convert来处理还是我们使用模型来处理,都是需要我们手动进行的,不仅仅效率比较低,出错的概率也会比较大,在序列化的过程中可能因为一些很细小的错误,导致我们花费大量的时间排查其中的问题,这就对开发者是很不友好了,那有没有什么能帮助我们自动进行JSON的序列化处理的呢,答案也是有,下面就是我们Flutter处理JSON序列化的主角:json_serializable

首先要把json_serializable导入到我们项目中的话,还需要一个常规和两个开发依赖项,具体得我们看看pubspec.yaml添加的内容:

  # Your other regular dependencies here
json_annotation: ^4.4.0 # Your other dev_dependencies here
json_serializable: ^6.1.5
build_runner: ^2.1.8

      注意: 这几个插件的版本具体的是跟着我自己的Flutter版本变化的,它们之间版本是相互有影响的,我没记错在执行命令生成g.dart文件的时候,版本不对还有错误产生,具体的错误我之前也忘记没有收集,在这就只能大概的提一句,要真的遇上问题的小伙伴,也可以朝着这个方向去解决查找问题。

有了这几个插件之后,我们接着往后面看该怎么处理, 在官网是给我们一个User的model的处理,具体的代码如下,我们可以参考学习下,并且注意下代码里面注释的内容:

import 'package:json_annotation/json_annotation.dart';

// user.g.dart 将在我们运行生成命令后自动生成
part 'user.g.dart'; ///这个标注是告诉生成器,这个类是需要生成Model类的
@JsonSerializable() class User{
User(this.name, this.email); String name;
String email;
//不同的类使用不同的mixin即可
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}

注意:还有一个关键词@JsonKey,比如我们的接口返回一个字段A,但是在模型中我们想使用字段B代替接口返回的A,那我们就可以使用@JsonKey关键字。我们举一个很现实的例子,就像你在iOS中,服务端接口给您返回一个id,你项目在使用OC的情况下是没办法在model中直接使用id接收的,因为关键字冲突,所以我们会处理成ID或者别的去接收,大概就是这么个情况,理解就可以了。

  /// Tell json_serializable that "registration_date_millis" should be
/// mapped to this property.
@JsonKey(name: 'id')
final int goodsId;

但在具体的开发中我们也需要自己给model中写这些代码吗?是的,但我推荐给大家一个可以帮我们生成model的地方。   【我在这里-为了便利使用json_serializable库

有几个小地方需要我们注意下,标注出来了,处理完之后你需要的就只是复制了。

这样你复制了内容,创建自己的model.dart文件,里面会有一些引用的错误,你可以不必理会,等我们处理完之后会顺带这修复的,接下来就是运行下面的命令来生成我们的序列化模板,在我们的项目根目录下运行:

flutter packages pub run build_runner build

我们可以在需要时为我们的model生成json序列化代码。 这触发了一次性构建,它通过我们的源文件,挑选相关的并为它们生成必要的序列化代码。虽然这非常方便,但如果我们不需要每次在model类中进行更改时都要手动运行构建命令的话会更好。那我们有办法持续性的生成序列化模板吗,答案是肯定的,接下来我们再运行命令:

flutter packages pub run build_runner watch

这个命令就帮助我们在项目根目录下运行来启动_watcher_,只需启动一次观察器,然后并让它在后台运行,这是安全的。具体的表现就像下面的动图一样的,在我们创建好我们的TestModel.dart文件之后,我们只需要保存,后面的序列化模板(TestModel.g.dart)文件也会随着自己生成,这就是前面命令运行完之后的持续性生成序列化模板的作用。

这样我们持续在创建g.dart文件,我们的序列化准备工作也就完成了,具体的序列化的代码我们在下面网络请求到出局之后一起看。

三:网络请求和JSON序列化


在Flutter的网络请求插件中,不得不提的使我们的Dio,在Pub上好评率很高,并且在GitHub也收获了近万Star。官方文档是这样描述Dio的:Dio是一个强大的DartHttp请求库,支持RestfulAPI、FormData、拦截器、请求取消、Cookie管理、文件上传/下载、超时、自定义适配器等...可以说是覆盖了所有涉及到的网络请求。 并且是国人开源的,所以我们只需要利用这个插件就足以应付Flutter的各种网络请求需求了。关于这个插件的具体使用我们不在这里赘述,的确网上太多太多的资料供大家查阅。

Dio Git地址】 前面提了这是国人开源的,大家可以翻阅中文开发文档查阅问题更方便。

这是Git给的一个例子,使用也是很简单,但具体根据自己项目进行封装等的就需要自己去处理。

import 'package:dio/dio.dart';
void getHttp() async {
try {
var response = await Dio().get('http://www.google.com');
print(response);
} catch (e) {
print(e);
}
}

下面是我们自己项目中具体的一些处理,前面说的我们处理好序列化的东西后就可以在请求到数据后直接处理成model了,重点就在

Responded<T> result = Responded<T>.fromJson(data);

static void send<T>(Request req,
{SuccessObj<T>? success,
SuccessObjList<T>? successList,
Failure? failure}) async {
try {
// 创建dio
Dio dio = _createDio();
// dio发起请求
var response = await _convertToDio(dio, req);
// 拿到的数据做一个简单的解码
var data = jsonDecode(response.toString());
// 解析成我们需要的数据模型
Responded<T> result = Responded<T>.fromJson(data);
if (result.code == 200) {
if (result.dataArray != null) {
if (successList != null) {
successList(result.dataArray);
}
} else {
if (success != null) {
if (result.data != null) {
success(result.data!);
} else {
if (failure != null) {
failure(Exceptions(result.code!, "没有相关数据!!"));
}
}
}
}
} else {
var exception = result.exception;
// ignore: prefer_conditional_assignment
if (null == exception) {
exception = Exceptions(result.code!, result.message ??= "");
}
if (failure != null) {
failure(exception);
}
}
} catch (e) {
if (failure != null) {
if (e is DioError) {
failure(Exceptions.create(e));
}
}
}
}

在我们生成的g.dart文件中,重点就是就是我们需要的编码和解析的方法,比如我写的测试demo中:

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'BodyModel.dart';

// **************************************************************************
// JsonSerializableGenerator
// ************************************************************************** BodyModel _$BodyModelFromJson(Map<String, dynamic> json) => BodyModel(
json['userId'] as int,
json['id'] as int,
json['title'] as String,
json['body'] as String,
); Map<String, dynamic> _$BodyModelToJson(BodyModel instance) => <String, dynamic>{
'userId': instance.userId,
'id': instance.id,
'title': instance.title,
'body': instance.body,
};

至此,关于Flutter网络请求和JSON序列化的东西我们就基本上梳理完了,小伙伴要疑问,可以留言或者私信我,一起学习探索。

编写本文章时候的Flutter版本:

---------------------------------------------------------------

➜  mixedflutter flutter --version

Flutter 2.10.5 • channel stable • https://github.com/flutter/flutter.git

Framework • revision 5464c5bac7 (3 weeks ago) • 2022-04-18 09:55:37 -0700

Engine • revision 57d3bac3dd

Tools • Dart 2.16.2 • DevTools 2.9.2

---------------------------------------------------------------

Flutter网络请求和数据解析的更多相关文章

  1. Android网络请求与数据解析,使用Gson和GsonFormat解析复杂Json数据

    版权声明:未经博主允许不得转载 一:简介 [达叔有道]软件技术人员,时代作者,从 Android 到全栈之路,我相信你也可以!阅读他的文章,会上瘾!You and me, we are family ...

  2. Flutter网络请求与JSON解析

    本文介绍如何在Flutter中创建HTTP网络请求和对请求的json string进行类型解析. 网络请求 官方使用的是用dart io中的HttpClient发起的请求,但HttpClient本身功 ...

  3. iOS网络请求之数据解析

    JSON解析 IOS中Json解析的四种方法 NSURLConnection-网络请求浅析 IOS开发:官方自带的JSON使用 XML 解析 GDataXMLNode应用 IOS学习:常用第三方库(G ...

  4. Android okHttp网络请求之Json解析

    前言: 前面两篇文章介绍了基于okHttp的post.get请求,以及文件的上传下载,今天主要介绍一下如何和Json解析一起使用?如何才能提高开发效率? okHttp相关文章地址: Android o ...

  5. 初探iOS网络开发,数据解析。

    通过大众点评平台开发来简单了解一下,oc的网络编程和数据解析(json) 首先我们需要到大大众点评开发者平台申请一个key.http://developer.dianping.com/app/tech ...

  6. 使用Charles进行网络请求抓包解析

    使用Charles进行网络请求抓包解析 0. 懒人的福音(⌐■_■)(破解版下载地址,记得安装java库支持) http://pan.baidu.com/s/1c08ksMW 1. 查看电脑的ip地址 ...

  7. C#网络请求与JSON解析

    最新学校的海康摄像头集控平台(网页端)不能在win10里登录,我寻思着拿海康的c# demo直接改. 首先得解决权限问题,每个教师任教不同年级,只能看到自己所在年级的设备,涉及到登录,在此记录一下C# ...

  8. Flutter 网络请求库http

    http 集成http库 https://pub.dartlang.org/packages/http 添加依赖 dependencies: http: ^ 安装 flutter packages g ...

  9. iOS 自己封装的网络请求,json解析的类

    基本上所有的APP都会涉及网络这块,不管是用AFNetWorking还是自己写的http请求,整个网络框架的搭建很重要. 楼主封装的网络请求类,包括自己写的http请求和AFNetWorking的请求 ...

随机推荐

  1. Linux的权限总结

    一般权限和特殊权限可控制 文件所有者.所有组.其他人的读写执行权限, 而隐藏权限则可以进行补充权限,可限制 文件内容只能追加内容,不更新属性等信息 ACL则可以进行让某个用户或组或other拥有指定文 ...

  2. 2. 使用Github

    2. 使用Github 2.1 目的 借助github托管项目代码 2.2 基本概念 仓库(Repository) 仓库用来存放项目代码,每个项目对应一个仓库,多个开源项目则有多个仓库 收藏(Star ...

  3. 从问题找原因之CSS浮动清除

    问题描述 浮动元素导致的后面img标签居中对齐"失败",如下图 <div> <div class="content1"> <div ...

  4. vue打包后空白页问题全记录 (background路径,css js404,jsonp等);

    总结一下vue打包后问题全记录:大部分开发者webpack基本上都是拿来就用的(并没有系统化的研究). 一 >>> 打包之后的静态文件不能直接访问:(例如dist)打包后搭个服务器才 ...

  5. [翻译]Service workers:PWA背后的英雄

    原文地址:https://medium.freecodecamp.org/service-workers-the-little-heroes-behind-progressive-web-apps-4 ...

  6. 跳转到下一页面时,必须先勾选阅读xx须知/协议才可跳转功能

    当跳转到新的html页面时,先判断checkbox是否选中,选中-->跳转到新页面:未选中--弹出提示消息(请先同意须知) HTML: 1 <div class="choose& ...

  7. 从数据库中获取图片编号,然后通过request获取图片下载

    import pandas as pd from pandas.core.dtypes.dtypes import register_extension_dtype from sqlalchemy i ...

  8. linux中LNMP架构和location用法

    location 使用Nginx Location可以控制访问网站的路径,但一个server可以有多个location配置, 多个location的优先级该如何区分 location匹配符号 匹配符 ...

  9. hibernate select查询方式总结

    https://www.cnblogs.com/xingege/p/4270990.html

  10. 使用Lua 脚本实现redis 分布式锁,报错:ERR Error running script (call to f_8ea1e266485534d17ddba5af05c1b61273c30467): @user_script:10: @user_script: 10: Lua redis() command arguments must be strings or integers .

    在使用SpringBoot开发时,使用RedisTemplate执行 redisTemplate.execute(lockScript, redisList); 发现报错: ERR Error run ...