首页
留言
关于
友链
更多
足迹
Search
1
SpringMVC+Spring+MyBatis整合完整版Web实例(附数据)
2,817 阅读
2
关于在Flutter实现Google地图的方法
1,606 阅读
3
druid报异常 “sql injection violation, part alway true condition not allow”的解决方案
1,181 阅读
4
MyBatis的TooManyResultsException异常的解决办法
973 阅读
5
如何去掉vue路径中的“#”号
968 阅读
发现
技术
生活
户外
登录
Search
标签搜索
Git
JavaScript
Oracle
Git学习
Java
Flutter
MySQL
SQL Server
IntelliJ IDEA
Spring Boot
Flutter 2.0
对称加密算法
Google地图
Maven
ES6
秦岭户外
linux
Tomcat
Redis
Spring
Bai Keyang
累计撰写
280
篇文章
累计收到
277
条评论
首页
栏目
发现
技术
生活
户外
页面
留言
关于
友链
足迹
搜索到
5
篇与
Flutter 2.0
的结果
2022-08-12
Flutter2.x 将Http请求结果转为Dart
在Flutter 2.x版本中将Http返回的结果转Dart稍微和前几个版本有些许差异,具体演示说明如下。Ps:在这里我用一个网上的开源api来示例请求接口地址:https://v1.hitokoto.cn/接口返回的Json对象如下:{ "id":3931, "uuid":"afc68395-6e1c-429c-b322-f1b7f4d43eba", "hitokoto":"嘿!活着是件很好的事", "type":"e", "from":"原创", "from_who":null, "creator":"Great old ones", "creator_uid":2073, "reviewer":0, "commit_from":"web", "created_at":"1538200036", "length":10 }json对应的类对象如下:class OneSentence { int id; String? hitokoto; String uuid; String? type; String? from; String? fromWho; String? creator; int? creatorUid; int reviewer; String? commitFrom; String? createdAt; int length; OneSentence( this.id, this.hitokoto, this.uuid, this.type, this.from, this.fromWho, this.creator, this.creatorUid, this.reviewer, this.commitFrom, this.createdAt, this.length); factory OneSentence.fromJson(Map<String, dynamic> json) { return OneSentence( json['id'], json['hitokoto'], json['uuid'], json['type'], json['from'], json['from_who'], json['creator'], json['creator_uid'], json['reviewer'], json['commit_from'], json['created_at'], json['length']); } Map<String, dynamic> toJson() { final Map<String, dynamic> data = new Map<String, dynamic>(); data['id'] = this.id; data['hitokoto'] = this.hitokoto; data['uuid'] = this.uuid; data['type'] = this.type; data['from'] = this.from; data['from_who'] = this.fromWho; data['creator'] = this.creator; data['creator_uid'] = this.creatorUid; data['reviewer'] = this.reviewer; data['commit_from'] = this.commitFrom; data['created_at'] = this.createdAt; data['length'] = this.length; return data; } } 请求http获取api结果:import 'dart:convert'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_demo/bean/OneSentence.dart'; class HttpPage extends StatefulWidget { const HttpPage({Key? key}) : super(key: key); @override _HttpPageState createState() => _HttpPageState(); } class _HttpPageState extends State<HttpPage> { String _text = ""; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Http请求"), leading: GestureDetector( onTap: () { Navigator.pop(context); }, child: Icon(Icons.arrow_back), ), ), body: Container( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded(child: ListView( children: [ Text(_text), ElevatedButton( onPressed: () => httpGet('https://v1.hitokoto.cn/', getOneSentence), child: Text('一言API')), ], )) ], ), ), ); } // 解析并转换 OneSentence getOneSentence(String res) { String _result = res; JsonCodec j = new JsonCodec(); OneSentence ons = OneSentence.fromJson(j.decode(_result)); setState(() { this._text = j.encode(ons.toJson()); }); return ons; } // 请求API并获取请求结果 void httpGet(String url, Function call) { HttpClient _httpClient = new HttpClient(); String _result = ""; _httpClient.getUrl(Uri.parse(url)) .then((HttpClientRequest request) => request.close()) .then((HttpClientResponse response) { if(response.statusCode == 200) { response.transform(utf8.decoder).join().then((value) { _result = value; call(_result); } ); } else { print('error'); _result = 'error'; call(_result); } } ); } }
2022年08月12日
110 阅读
0 评论
0 点赞
2021-12-25
Flutter 2.0空安全之数据模型(Model)空安全适配技巧
数据模型(Model)空安全适配主要以下两种情况:含有命令构造函数的模型含有命名工厂构造函数的模型含有命令构造函数的模型含有命令构造函数的模型的空安全适配技巧:适配前:///数据模型 class ItemModel { int totalCount; List<Item> resultList; ItemModel.fromJson(Map<String, dynamic> json) { totalCount = json['totalCount']; if (json['resultList'] != null) { resultList = new List<Item>(); json['resultList'].forEach((v) { resultList.add(new Item.fromJson(v)); }); } } Map<String, dynamic> toJson() { final Map<String, dynamic> data = new Map<String, dynamic>(); data['totalCount'] = this.totalCount; if (this.resultList != null) { data['resultList'] = this.resultList.map((v) => v.toJson()).toList(); } return data; } }适配之前首先要和后端服务协商好,在数据模型中那些字段可空,那些字段是不为空的。以上代码中假如:totalCount字段是一定会有数据,resultList字段是不能保证有数据,那么我们可以这样来适配:适配后:///数据模型 class ItemModel { late int totalCount; List<Item>? resultList; //命名构造方法 ItemModel.fromJson(Map<String, dynamic> json) { totalCount = json['totalCount']; if (json['resultList'] != null) { resultList = new List<Item>.empty(growable: true); json['resultList'].forEach((v) { resultList!.add(new Item.fromJson(v)); }); } } Map<String, dynamic> toJson() { final Map<String, dynamic> data = new Map<String, dynamic>(); data['totalCount'] = this.totalCount; data['resultList'] = this.resultList!.map((v) => v.toJson()).toList(); return data; } }对于一定会下发的字段我们通过late来修饰为延迟初始化的字段以方便访问对于不能保证一定会下发的字段,我们通过?将其修饰为可空的变量含有命名工厂构造函数的模型命名工厂构造函的数据模型也是比较常见的数据模型之一,有命名工厂构造函的数据模型的空安全适配技巧如下:适配前:class ResponseResult { /// 成功标记 true:成功;false:失败 bool status; /// 消息 String info; /// 数据 dynamic data; ResponseResult({this.status, this.info, this.data}); factory ResponseResult.fromJson(Map<String, dynamic> json) { return ResponseResult( status: json['status'], info: json['info'], data: json['data'] ); } @override String toString() { return 'ResponseResult{status: $status, info: $info, data: $data}'; } Map<String, dynamic> toJson () { Map<String, dynamic> _m = new Map<String, dynamic>(); _m["status"] = this.status; _m["info"] = this.info; _m["data"] = this.data; return _m; } }含有命名工厂构造函数的模型通常需要有自己的构造函数,构造函数通常采用可选参数,所以在进行适配时首先要明确哪些字段一定不为空,哪些字段可空,确认好之后就可以进行下面适配了:适配后:class ResponseResult { /// 成功标记 true:成功;false:失败 bool status; /// 消息 String? info; /// 数据 dynamic? data; ResponseResult({required this.status, this.info, this.data}); factory ResponseResult.fromJson(Map<String, dynamic> json) { return ResponseResult( status: json['status'], info: json['info'], data: json['data'] ); } @override String toString() { return 'ResponseResult{status: $status, info: $info, data: $data}'; } Map<String, dynamic> toJson () { Map<String, dynamic> _m = new Map<String, dynamic>(); _m["status"] = this.status; _m["info"] = this.info; _m["data"] = this.data; return _m; } }对于可空的字段通过?进行修饰对于不可空的字段,需要在构造方法中在对应的字段前面添加required修饰符来表示这个参数是必传参数
2021年12月25日
154 阅读
0 评论
0 点赞
2021-12-08
Flutter 2.0空安全之自定义Widge适配
自定义Widget的空安全适配分两种情况:Widget的空安全适配State的空安全适配Widget的空安全适配对于自定的Widget无论是页面的某控件还是整个页面,通常都会为Widget定义一些属性。在进行空安全适配时要对属性进行一下分类:可空的属性:通过?进行修饰不可空的属性:在构造函数中设置默认值或者通过 required 进行修饰class WebView extends StatefulWidget { String? url; final String? statusBarColor; final String? title; final bool? hideAppBar; final bool backForbid; WebView( {this.url, this.statusBarColor, this.title, this.hideAppBar, this.backForbid = false}) ...上述示例是WebView模块进行空安全适配后的效果。提示:如果构造方法中使用了 @required 那么需要改成 required 。State的空安全适配State的空安全适配主要是根据它的成员变量是否可空进行分类:可空的变量:通过 ? 进行修饰不可空的变量:可采用以下两种方式进行适配:定义时初始化;使用 late 修饰为延时变量下面是项目中的State适配了空安全后的主要代码效果可以参考下:class _TravelPageState extends State<TravelPage> with TickerProviderStateMixin { late TabController _controller; //延时初始 List<TravelTab> tabs = []; //定义时初始化 ... @override void initState() { super.initState(); _controller = TabController(length: 0, vsync: this); ...
2021年12月08日
169 阅读
0 评论
0 点赞
2021-12-06
Flutter 2.0空安全之手动关闭/开启
Flutter 2默认启用了空安全,所以通过Flutter 2创建的项目是已经开启了空安全的检查的,另外,也可以可以通过下面命令来查看你的Flutter SDK版本:flutter doctor那么,如何手动开启和关闭空区安全的?environment: sdk: ">=2.12.0 <3.0.0" //sdk >=2.12.0表示开启空安全检查提示:一旦项目开启了空安全检查,那么你的代码包括项目所依赖的三方插件必须是要支持空安全的否则是无法正常编译的。开启空安全之后,然后运行下项目你会看到很多的报错,然后定位到报错的文件,对项目进行空安全适配。如果想关闭空安全检查,可以将SDK的支持范围调整到2.12.0以下即可,如:environment: sdk: ">=2.7.0 <3.0.0"
2021年12月06日
262 阅读
0 评论
0 点赞
2021-12-05
Flutter 2.0空安全之最小必备知识
Flutter 2.0空安全之最小必备知识从Flutter 2开始,Flutter便在配置中默认启用了空安全,通过将空检查合并到类型系统中,可以在开发过程中捕获这些错误,从而防止再生产环境导致的崩溃。{dotted startColor="#ff6c6c" endColor="#1989fa"/}什么是空安全时至今日,空安全已经是一个屡见不鲜的话题,目前像主流的编程语言Kotlin、Swift、Rust 等都对空安全有自己的支持。Dart从2.12版本开始支持了空安全,通过空安全开发人员可以有效避免null错误崩溃。空安全性可以说是Dart语言的重要补充,它通过区分可空类型和非可空类型进一步增强了类型系统。引入空安全的好处可以将原本运行时的空值引用错误将变为编辑时的分析错误;增强程序的健壮性,有效避免由Null而导致的崩溃;跟随Dart和Flutter的发展趋势,为程序的后续迭代不留坑;空安全最小必备知识空安全的原则引入空安全前后Dart类型系统的变化可空(?)类型的使用延迟初始化(late)的使用空值断言操作符(!)的使用空安全的原则Dart 的空安全支持基于以下三条核心原则:默认不可空:除非您将变量显式声明为可空,否则它一定是非空的类型;渐进迁移:您可以自由地选择何时进行迁移,多少代码会进行迁移;完全可靠:Dart 的空安全是非常可靠的,意味着编译期间包含了很多优化,如果类型系统推断出某个变量不为空,那么它 永远 不为空。当您将整个项目和其依赖完全迁移至空安全后,您会享有健全性带来的所有优势——更少的 BUG、更小的二进制文件以及更快的执行速度。引入空安全前后Dart类型系统的变化在引入空安全前Dart的类型系统是这样的: 这意味着在之前,所有的类型都可以为Null,也就是Nul类型被看作是所有类型的子类。在引入空安全之后: 可以看出,最大的变化是将Null类型独立出来了, 这意味着Null不在是其它类型的子类型,所以对于一个非Null类型的变量传递一个Null值时会报类型转换错误 。提示:在使用了空安全的Flutter或Dart项目中你会经常看到 ?.、!、late 的大量应用,那么他们分别是什么又改如何使用呢?请看下文的分析可空(?)类型的使用我们可以通过将 ? 跟在类型的后面来表示它后面的变量或参数可接受Null:class CommonModel { String? firstName; //可空的成员变量 int getNameLen(String? lastName /*可空的参数*/) { int firstLen = firstName?.length ?? 0; int lastLen = lastName?.length ?? 0; return firstLen + lastLen; } }对于可空的变量或参数在使用的时候需要通过Dart 的避空运算符 ?. 来进行访问,否则会抛出编译错误。当程序启用空安全后,类的成员变量默认是不可空的,所以对于一个非空的成员变量需要指定其初始化方式class CommonModel { List names=[];//定义时初始化 final List colors;//在构造方法中初始化 late List urls;//延时初始化 CommonModel(this.colors); ...延迟初始化(late)的使用对于无法在定义时进行初始化,并且又想避免使用 ?. ,那么延迟初始化可以帮到你。通过 late 修饰的变量,可以让开发者选择初始化的时机,并且在使用这个变量时可以不用 ?. 。 late List urls;//延时初始化 setUrls(List urls){ this.urls=urls; } int getUrlLen(){ return urls.length; }延时初始化虽然能为我们编码带来一定便利,但如果使用不当会带来空异常的问题,所以在使用的时候一定保证赋值和访问的顺序,切莫颠倒。扩展: 延迟初始化(late)使用范式在Flutter中State的 initState 方法中初始化的一些变量是比较适合使用late来进行延时初始化的,因为在Widget生命周期中 initState 方法是最先执行的,所以它里面初始化的变量通过 late 修饰后既能保障使用时的便利,又能防止空异常,下面就来看下具体的用法:class _SpeakPageState extends State<SpeakPage> with SingleTickerProviderStateMixin { String speakTips = '长按说话'; String speakResult = ''; late Animation<double> animation; late AnimationController controller; @override void initState() { controller = AnimationController( super.initState(); vsync: this, duration: Duration(milliseconds: 1000)); animation = CurvedAnimation(parent: controller, curve: Curves.easeIn) ..addStatusListener((status) { if (status == AnimationStatus.completed) { controller.reverse(); } else if (status == AnimationStatus.dismissed) { controller.forward(); } }); } ...空值断言操作符(!)的使用当我们排除变量或参数的可空的可能后,可以通过 ! 来告诉编译器这个可空的变量或参数不可空,这对我们进行方法传参或将可空参数传递给一个不可空的入参时特别有用: Widget get _listView { return ListView( children: <Widget>[ _banner, Padding( padding: EdgeInsets.fromLTRB(7, 4, 7, 4), child: LocalNav(localNavList: localNavList), ), if (gridNavModel != null) Padding( padding: EdgeInsets.fromLTRB(7, 0, 7, 4), child: GridNav(gridNavModel: gridNavModel!)), Padding( padding: EdgeInsets.fromLTRB(7, 0, 7, 4), child: SubNav(subNavList: subNavList)), if (salesBoxModel != null) Padding( padding: EdgeInsets.fromLTRB(7, 0, 7, 4), child: SalesBox(salesBox: salesBoxModel!)), ], ); }上述代码是根据gridNavModel与salesBoxModel模块数据是否为空时动态创建的列表,在确保变量不为空的情况下使用了空值断言操作符!。除此之外, ! 还有一个常见的用处:bool isEmptyList(Object object) { if (object is! List) return false; return object.isEmpty; }用在这里表示取反,上述代码等价于:bool isEmptyList(Object object) { if (!(object is List)) return false; return object.isEmpty; }
2021年12月05日
139 阅读
0 评论
0 点赞