按钮扁平化用法示例-buildFlatButton

Widget buildFlatButton() {
    return Align(
      alignment: const Alignment(0.0, -0.2),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          ButtonBar(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              FlatButton(
                child: const Text('FLAT BUTTON', semanticsLabel: 'FLAT BUTTON 1'),
                onPressed: () {
                  // Perform some action
                },
              ),
              const FlatButton(
                child: Text('DISABLED', semanticsLabel: 'DISABLED BUTTON 3',),
                onPressed: null,
              ),
            ],
          ),
          ButtonBar(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              FlatButton.icon(
                icon: const Icon(Icons.add_circle_outline, size: 18.0),
                label: const Text('FLAT BUTTON', semanticsLabel: 'FLAT BUTTON 2'),
                onPressed: () {
                  // Perform some action
                },
              ),
              FlatButton.icon(
                icon: const Icon(Icons.add_circle_outline, size: 18.0),
                label: const Text('DISABLED', semanticsLabel: 'DISABLED BUTTON 4'),
                onPressed: null,
              ),
            ],
          ),
        ],
      ),
    );
  }

 

 

 

 

 

  factory FlatButton.icon({
    Key key,
    @required VoidCallback onPressed,
    ValueChanged<bool> onHighlightChanged,
    ButtonTextTheme textTheme,
    Color textColor,
    Color disabledTextColor,
    Color color,
    Color disabledColor,
    Color highlightColor,
    Color splashColor,
    Brightness colorBrightness,
    EdgeInsetsGeometry padding,
    ShapeBorder shape,
    Clip clipBehavior,
    MaterialTapTargetSize materialTapTargetSize,
    @required Widget icon,
    @required Widget label,
  }) = _FlatButtonWithIcon;

 

 

 const FlatButton({
    Key key,
    @required VoidCallback onPressed,
    ValueChanged<bool> onHighlightChanged,
    ButtonTextTheme textTheme,
    Color textColor,
    Color disabledTextColor,
    Color color,
    Color disabledColor,
    Color highlightColor,
    Color splashColor,
    Brightness colorBrightness,
    EdgeInsetsGeometry padding,
    ShapeBorder shape,
    Clip clipBehavior = Clip.none,
    MaterialTapTargetSize materialTapTargetSize,
    @required Widget child,
  }) : super(
         key: key,
         onPressed: onPressed,
         onHighlightChanged: onHighlightChanged,
         textTheme: textTheme,
         textColor: textColor,
         disabledTextColor: disabledTextColor,
         color: color,
         disabledColor: disabledColor,
         highlightColor: highlightColor,
         splashColor: splashColor,
         colorBrightness: colorBrightness,
         padding: padding,
         shape: shape,
         clipBehavior: clipBehavior,
         materialTapTargetSize: materialTapTargetSize,
         child: child,
      );

 

7 of 7 in the series: Fltter移动开发相关

每周学习第二期 (2019-01-11)

新闻

向老前辈,致敬!!!
一句话新闻
  • 统计显示,美国55%的智能手机用户、全世界86%的智能手机用户,使用安卓系统。
  • GitHub 宣布,个人用户可以免费使用私有库,数量不限,该功能以前是付费使用。
  • 印度的2018年安卓应用程序排行榜里面,前10名有5个来自中国,2017年是2个;前100名有44个来自中国,2017年是18

 

 

5G 通信的频率(3300-3600MHz 和 4800-5000MHz)比 4G (1880-1900MHz、2320-2370MHz、2575-2635MHz)高很多。频率越高,覆盖能力越差,这注定很多角落收不到 5G 信号,所以需要修建更多的信号发射装置。
英国沃达丰公司的工程师提出,可以使用城市的下水道盖子,作为无线信号的发射基地。这样不会占用地面空间,外部也看不到

 

 

诺丁汉大学发明了一种微型太阳能电池,每个发电单元的长度为3毫米,宽度为1.5毫米,可以嵌入纱线,进而编织成服装,使得后者具备发电功能,而且肉眼还看不出任何差别。电池封装在树脂之中,所以纺织品可以进行洗涤,也不怕磨损。
用户穿上这种纺织品,就可以发电。该技术已经过测试,能够为手机充电。一块5厘米×5厘米大小的纺织品,可以放置多达200个发电单元,产生2.5-10伏特和高达80毫瓦的功率,如果发电单元达到2000个,就能为手机充电。

 

 

斯坦福大学的科学家将电极植入瘫痪病人的大脑皮层,接受脑电波,转为数字信号,控制无线蓝牙鼠标,操作平板电脑。参与实验的患者,可以使用常见程序(网页浏览、电子邮件、聊天、发送短信等)。
这项发明不仅对瘫痪者有用,长期来看,可能会为意念操作电脑创造可能性。

 

 

美国路易斯安娜州开始采用数字驾照。用户下载一个 App,输入自己的物理驾照的信息,然后 App 会将这些信息提交到州政府的机动车辆数据库进行验证。通过验证,App 就会生成一个二维码。
需要驾照的场合,警察就可以拿自己的手机扫描 App 的二维码,从数据库返回这个驾照的信息。

学习资料

伯克利大学最新深度学习课程资料中文版下载

关于本书

本教材是加州大学伯克利分校 2019 年春学期《 Introduction to Deep Learning 》课程教材,伯克利的CS(计算机科学)是非常强的。由于伯克利就在湾区(硅谷),所以他们的计算机大佬们即是学术精英,也是业界大拿。本课程主要由李沐老师开设,基本上涵盖了深度学习的方方面面,可以说是一门比较全的参考资料了,
链接:https://pan.baidu.com/s/1-RGOQaD6Jr5Inks476MquQ
密码:k1q8

「优秀开源AI项目推荐」vid2vid:超逼真高清视频生成

英伟达和MIT的研究团队高出一个超逼真高清视频生成AI。
只要一幅动态的语义地图,就可获得和真实世界几乎一模一样的视频。换句话说,只要把你心中的场景勾勒出来,无需实拍,电影级的视频就可以自动P出来:
这背后的vid2vid技术,是一种在生成对抗性学习框架下的新方法:精心设计的生成器和鉴别器架构,再加上时空对抗目标。
研究论文:https://tcwang0509.github.io/vid2vid/paper_vid2vid.pdf
GitHub地址:https://github.com/NVIDIA/vid2vid

数码

在,网络技术越来越发达,无线网络覆盖越来越广泛,移动网络已经不满足于我们,WiFi的使用率就越来越多,在外面想要连接WiFi,但是外面的无线网络设置了密码,怎么连接呢?这时可能我们会想到WiFi万能钥匙,并不是所有的密码都可以破解,当然也可以破解一部分吗,除了WiFi万能钥匙,小编还寻到一款比较不错的无线密码破解工具ewsa,全称为Elcomsoft Wireless Security Auditor,拥有强大的密码破解能力,该软件通过密码词典去尝试破解无线AP上的WPA和WPA2密码,一般密码由8位数的字符组成,所有你可以使用暴力破解、字典破解等常用的破解方式来破解密码,帮助你轻松获得无线WiFi的密码,蹭网轻松松松。不仅支持密码破解,它还支持WiFi信号搜索功能,比如笔记本等移动设备都可以搜索WiFi信号,然后快速进行密码破解。而且对于你经常需要用的WiFi信号源提供记录功能,下次使用可以直接进行连接,无需重新破解,非常方便。

IT

第一名 GitKraken

适用于Windows、Mac和Linux的Git 客户端。在2018年,超过100万用户,连续3年获得用户最佳!
下载地址:https://www.gitkraken.com/git-client
  1. 压轴出场:微软主打的革命性开发扩展:VS Live Share,在这个扩展的加持下,你可以和你的同事完成真正的远程实时代码协同开发,对方并不需要将整个工程clone下来,只需要连接到你开的session,你和他就可以对一个文件进行开发,修改。

抖音热门视频制作工具,都在这儿了!

一、抖音数据分析平台
1)西瓜短视频助手
监测视频热度、音乐热度、主播热度工具,网页版和微信小程序都有
2)Kolranking
收集和监测大部分头部的账号,更多的是通过API 抓取抖音视频数据,做成了榜单形式
二、去水印工具
1)水印宝、InShot (功能强大,还有自由裁剪功能)
这些软件和APP 各有优缺点,有一些是付费的功能
三、字体工具
1)尖叫字体生成工具
2)文字翻转特效制作工具:字说、美册
3)变声APP :配音变声器、VoiceChanger
四、视频剪辑和字幕添加工具
Pr(专业级软件,电脑操作,较复杂) 、Ae 、巧影、Videoleap(苹果手机)、快剪辑、爱剪辑、印象、VUE
五、抖音视频拍摄
1)录屏:录屏大师、录制屏幕视频工具

一个不收集隐私的搜索引擎duckduckgo.com

python

JAVA

Spring Boot 的 10 个核心模块

1、spring-boot
这是 Spring Boot 的主模块,也是支持其他模块的核心模块,主要包含以下几点:
1) 提供了一个启动 Spring 应用的主类,并提供了一个相当方便的静态方法,它的主要是作用是负责创建和刷新 Spring 容器的上下文;
2) 内嵌式的并可自由选择搭配的 WEB 应用容器,如:Tomcat, Jetty, Undertow等;
3) 对配置外部化的支持;
4) 提供一个很方便的 Spring 容器上下文初始化器,包括合理记录日志默认参数的支持。
2、spring-boot-autoconfigure
Spring Boot能根据类路径下的内容自动一些公共大型应用,提供的@EnableAutoConfiguration 注解就能启用 Spring 功能的自动配置。
自动配置功能可以推断用户可能需要加载哪些 Spring Bean, 如:如果类路径下有HicariCP 这个连接池的包,此时并未提供任何有效连接池的配置,那么 Spring Boot 就知道你可能需要一个连接池,并做相应配置。如果用户配置了其他连接池,那么 Spring Boot 会放弃自动配置。
3、spring-boot-starters
Starters,我们叫它启动器好了,它是包括一系列依赖的描述符。简单的说就是,它可以一站式的帮你打包 Spring 及相关技术应用,而不需要你到处找依赖和示例配置代码,它都帮你做好了。
例如,第一章我们在介绍 Spring Boot 的时候就说了 spring-boot-starter-web 这个启动器,你只要引用了这个启动器应用,就会自动配置 WEB 应用的能力。
spring-boot-starters 这个启动器这主要提供了 spring-boot, spring-context,spring-beans 这三个 Spring 模块而已。
4、spring-boot-cli
这是 Spring Boot 的命令行工具,用于编译和运行 Groovy 源程序,可以十分简单的编写并运行一个应用程序。它也能监控你的文件,一旦有变动就会自动重新编译和重新启动应用程序。
5、spring-boot-actuator
这是 Spring Boot 提供的执行端点,你可以更好的监控及和你的应用程序交互。这个模块提供了像健康端点、环境端点、Spring Bean端点等。
6、spring-boot-actuator-autoconfigure
这个原理同上,为 Spring Boot 执行端点提供自动配置。
7、spring-boot-test
Spring Boot测试模块,为应用测试提供了许多非常有用的核心功能。
8、spring-boot-test-autoconfigure
这个原理同上,为 Spring Boot 测试模块提供自动配置。
9、spring-boot-loader
这个模块可以用来构建一个单独可执行的 jar 包,使用 java -jar 就能直接运行。一般不会直接使用这个来打包,使用 Spring Boot 提供的 Maven 或者 Gradle 插件就行了。
10、spring-boot-devtools
开发者工具模块,主要为 Spring Boot 开发阶段提供一些特性,如修改了代码自动重启应用等。这个模块的功能是可选的,只限于本地开发阶段,当打成整包运行时这些功能会被禁用。

Java工具包,提高开发效率,里面应有尽有Hutoo

Hutool是一个Java工具包,也只是一个工具包,它帮助我们简化每一行代码,减少每一个方法,让Java语言也可以“甜甜的”。Hutool最初是作者(Looly)项目中“util”包的一个整理,后来慢慢积累并加入更多非业务相关功能,并广泛学习其它开源项目精髓,经过自己整理修改,最终形成丰富的开源工具集。

包含组件

一个Java基础工具类,对文件、流、加密解密、转码、正则、线程、XML等JDK方法进行封装,组成各种Util工具类,同时提供以下组件

 

  • hutool-aop JDK动态代理封装,提供非IOC下的切面支持
  • hutool-bloomFilter 布隆过滤,提供一些Hash算法的布隆过滤
  • hutool-cache 缓存
  • hutool-core 核心,包括Bean操作、日期、各种Util等
  • hutool-cron 定时任务模块,提供类Crontab表达式的定时任务
  • hutool-crypto 加密解密模块
  • hutool-db JDBC封装后的数据操作,基于ActiveRecord思想
  • hutool-dfa 基于DFA模型的多关键字查找
  • hutool-extra 扩展模块,对第三方封装(模板引擎、邮件、Servlet、二维码等)
  • hutool-http 基于HttpUrlConnection的Http客户端封装
  • hutool-log 自动识别日志实现的日志门面
  • hutool-script 脚本执行封装,例如Javascript
  • hutool-setting 功能更强大的Setting配置文件和Properties封装
  • hutool-system 系统参数调用封装(JVM信息等)
  • hutool-json JSON实现
  • hutool-captcha 图片验证码实现
  • hutool-poi 针对POI中Excel的封装
<dependency>
 <groupId>cn.hutool</groupId>
 <artifactId>hutool-all</artifactId>
 <version>4.4.0</version>
</dependency>

数据库

Web服务端/前端

walle 2.0.0 正式发布,可能是春节前最良心的免费开源部署工具

教程


1、文档站点生成工具(英文)
本文以 JS 项目为例,介绍各种生成文档站点的工具。
本文总结了历史上重大的软件创新,进而提出专利制度不适合软件业,应该废除软件专利。
3、Wireguard 安装教程(英文)
介绍 Wirdguard 如何安装和配置。
fx 可以方便地在命令行操作 JSON 数据,本文是 fx 用法的教程。
作者谈了他不喜欢的8个 Python 语法。
本文较通俗地介绍了神经网络的历史发展和计算原理。
7、10年博客的经验(英文)
作者写了10年博客,介绍怎么可以通过博客取得最佳效果。
假设放大镜可以无限大,能够聚焦月光以点火吗?答案是不能。
一个软件工程师介绍自己安装的 iOS 软件。

资源


 

 

该网站提供美国的好奇号火星车拍摄的多张火星全景照片,各种不同的地貌,可以360度旋转观看。
《Rust 编程语言》的 EPUB 版本下载,可以从这本书开始学习 Rust 语言。
字体搜索引擎。
该网站是数学知识科普,覆盖了代数,几何,统计,微积分等领域。有一个爱好者翻译的中文镜像。(@rolitter 投稿)
介绍如何搭建 OAuth 服务的电子书。
Linux 命令的搜索入口,提供中文解释。(@jaywcjlove__ __投稿)
7、Awesome Mac(中文版)
收入各种好用的 Mac 软件。(@jaywcjlove 投稿)、

工具


1、WBO
一个多人实时分享的在线白板。

 

 

国人开发的 MacOS 视频播放器,特点是点击文本字幕,会显示英语单词的中文解释,英语学习者的小帮手。

 

 

一个生成网页互动表格的 JS 库,提供很多功能。
各种云服务之间转移文件的命令行工具。

 

 

jerverless 是一个 Web 服务器,可以将任何语言的程序转为 Serverless 函数,从网络调用。它会把源程序放在 Docker 容器里面运行,然后提供 Web 接口与用户通信。
这个库可以根据击打键盘的声音,分析用户的输入内容。
7、fx
命令行 JSON 数据的浏览工具。
一种将 HTML 转成 JSON 格式的规范标准。
Puppeteer 现在不仅封装 Chrome,还开始封装 Firefox 了,API 完全一样。以后,浏览器自动化可能只用它就可以了,其他库都要被干掉了。
基于 vue + elementUI 构建的网站管理后台脚手架。(@umi-soft__ __投稿)
一款 Hexo 的主题,提供更好的用户体验和更清爽的UI设计。(@dongyuanxin 投稿)

文摘


英国科幻小说家亚瑟.C.克拉克,提出了三个定律。
克拉克的第一定律:“如果一位杰出的老科学家表示,某些事情是可能的,那么他几乎肯定是对的。如果他说某事是不可能的,他很可能是错的。”
克拉克还补充说,上面定律里面“老人”的定义,取决于他所在的学科。“物理学、数学和航天科技中,超过三十岁的人就是老人;其他学科中,老人有时会推迟到四十岁。当然也有一些了不起的例外,但是每个刚刚大学毕业的研究人员都知道,超过五十岁的科学家只能去参加会议,其他什么也干不了,而且他本人也应该有自知之明,绝不要让自己去碰实验室的工作。”
克拉克的第二定律:“发现极限的唯一方法,就是尝试一些不可能的事情。”
克拉克的第三定律:“任何足够先进的技术都像魔术一样。”
20世纪50年代开始,鸡肉消费量大幅增长,成了人类最多消费的肉类来源。如今,全世界一共存在210亿只鸡。
为了适应对鸡肉的需求,人类逐步改变了鸡这个物种,使得当代肉鸡与原始的野生鸡差异越来越大。
肉鸡的腿部和胸部肌肉,生长得特别快,而内脏(包括心脏和肝脏)则比野生鸡小。这意味着,肉鸡根本没法在野外生存,而且较多的鸡肉和较小的器官也限制了肉鸡的寿命。
科学家认为,肉鸡实际上是人工设计的物种,使其适合人类的食物消费,让它成为地球上数量最多的陆生脊椎动物。

 

 

声音是一种波,人耳能够听到的频率范围在 20Hz – 20kHz 之间。
为了将音频变成数字信号,需要对音频进行抽样。每秒之内的抽样次数越多,就能越好地还原声音。CD 质量的音频就是每秒进行抽样44100次,也就是 44.1kHz。由于至少两次抽样才能确定一个波峰或波谷,所以 44.1kHz 的抽样频率,最高可以记录 22kHz 频率的声音。
抽样频率越高,所能记录的声音频率也就越高。但是,人耳最高只能听到 20kHz 频率的声音,所以抽样频率太高,意义不大。另一方面,抽样频率太低,高频声音无法记录到,会影响音质。比如,电话质量的声音,抽样频率是 8KHz,因此记录不到 4kHz 以上的声音。
CD 质量的音频在抽样以后,使用16个二进制位保存每一次抽样结果。所以,每秒的数据量是 16位 x 44,100 x 2个立体声声道 = 1411.2kbps,即 176.4KB,保存成 wav 文件,一分钟就是10.1MB。
wav 文件体积太大,一首歌有几十MB,因此人们就发明了音频压缩技术,缩小音频文件的体积。“无损”的音频压缩(比如 FLAC、ALAC、MP3 HD 格式),跟普通的文件压缩技术并无太大不同。为了达到更好的压缩效果,一般都是使用“有损”的音频压缩(比如 MP3、AAC、WMA、Ogg Vorbis 格式)。它的原理是,随着年龄增长,中年人会逐渐听不到 16kHZ 以上的声音,所以这部分信号可以抛弃掉。
MP3 格式可以把每秒钟的数据量压缩到 128kbps(即 16KB),一分钟只有 960KB,比起 wav 格式小了90%多。

本周图片


 

 

Pepper 是一只1970年出生在实验室的大猩猩,她一直被用于医学研究,曾经307次被麻醉枪击倒,36次肝脏活检,1次开放式肝脏活组织检查,6次宫颈活检,10次淋巴结活检和4次骨髓活检,还被接种了艾滋病病毒。由于恐惧和焦虑,她在实验室生活的后期曾经拒绝饮食,宁愿饿死。
从出生开始,她一直住在一个 5米 x 5米 x 7米 的笼子,从未离开过。这样生活了27年以后,1997年,经过动物保护组织的争取,实验室同意将她移交给动物保护组织,她被转移到佛罗里达州一个专门收留实验猩猩的场所。上面的照片摄于2002年。他死于2012年,一共活了42岁。
像这样专门用于实验的大猩猩,在美国共有几百只。美国国立卫生研究院已经宣布,将退出其中的大部分。
2、珍珠宫(组图)

 

 

珍珠宫是上个世纪70年代,伊朗革命爆发之前,美国建筑师为伊朗国王的妹妹设计的住所,具有未来主义风格,如今已成废墟。本文是珍珠宫的介绍 + 照片。上图是整个建筑的模型,下图是室内游泳池。

 

 

2014年,人工智能已经可以生成人脸,但你可以很容易看出哪几张是机器生成的。下图都是那时人工智能生成的人脸。

 

 

2018年,AI 生成的人脸,就不太容易跟真实的人脸区分了。

 

 

本周金句


1、一个敢于浪费一小时生命的人并没有发现生命的价值。
— 查尔斯·达尔文
2、创建一个手机操作系统有多难?
2014年,六个移动操作系统企图替代 iOS 和 android:Blackberry OS,Sailfish,Ubuntu Mobile,Firefox OS,Tizen 和 Windows Phone,现在它们都死了或不再有这种可能。
3、如果你不懂 p 值这样的概念,然后企图在3-4个月内完成机器学习的课程,能够使用 R 和 Python 编写代码。这意味着,你可以成为一名营销分析师,并能处理一些数字,仅此而已。
4、一家公司想装修办公室地板,结果发现下面是蜿蜒曲折的通信电缆。如果彻底装修,必须更换并重新连接电缆。他们这样做了吗?没有,当他们看到复杂的电缆后,就没有碰任何东西,只是小心地更换了地板。谁知道每根电缆的作用和连接方式?最好保持原样。

2 of 4 in the series: 分享每一周

免费作图工具

本页收集一些免费的工具,创建漂亮的图表。

ProcessOn

在线版:https://www.processon.com/

yEd

桌面版:https://www.yworks.com/products/yed

在线版:https://www.yworks.com/products/yed-live

Pencil

桌面版:https://pencil.evolus.vn/

Dia

桌面版:http://dia-installer.de/

Inkscape

网址:https://inkscape.org/

Draw.io

在线版:https://www.draw.io/

桌面版:https://about.draw.io/integrations/#integrations_offline

Whimsical

在线版:https://whimsical.co/

PlantUML

在线版:http://www.plantuml.com/plantuml/

迅捷画图

在线版:https://www.liuchengtu.com/

百度脑图

在线版:http://naotu.baidu.com/

Visual Paradigm Online

在线版:https://online.visual-paradigm.com

Creately

在线版:https://creately.com/

Coggle

在线版:https://coggle.it

3 of 7 in the series: Fltter移动开发相关

每周学习第一期 (2019-01-04)

新闻

健康

学习资料

导师:“Ed,你在做什么?”我(骄傲的): “我在读一本有关使用 GWT 构建现代 Java 应用的书。”导师: “为什么?”我: “作为一名 Java 开发人员,我需要紧跟潮流。GWT 是流行趋势。”导师:“在 GWT 之前,你读过什么技术书籍?”我: “一本关于 Apache Tapestry 的 500 页的著作。 Tapestry 那时是流行趋势。”导师:“Tapestry 现在还流行吗?”我: “不流行了。现在流行 GWT。”导师:“你还可以重用 Tapestry 的技能来解决当前的问题吗?”我: “不能,现在没人用它了。”导师:“Tapestry 的知识能帮助你更好地理解 GWT 吗?”我: “不,不能。但我看到了一些重叠的模式。”导师:“那是设计模式。它们能帮你解决当前的问题吗?”我: “是的。可以解决其中许多问题。”导师:“技术变化无定,但有很多共同点。确定好优先级。将 80% 的学习时间投入到基础知识上。剩下的 20% 用于框架、库和工具。”我: “嗯…仅 20% 用于框架、库和工具?”导师:“是的。反正你在工作中解决问题的时候会学习它们。”我: “谢谢。”导师:“你以后会感谢我的。”

IT

  • 视频点位人流量分析”,基于深度学习和计算机视觉技术,可以实时统计监控视频中的经过人数及拥挤情况。也可以针对人员密集场所的监管需求,构建群体聚集分析模型,智能判断出某区域是否有拥挤堵塞、异常聚集等行为。
  • 禁入区域异常入侵预警”技术。识别系统通过深度学习人体特征和动作,能够自动发现、标记出人员的位置,当有人员异常入侵重点禁入区域时,以及异常行为时,系统可以发出自动预警。
  • 人员异常行为智能预警”系统,可以通过构建行为运动分析模型和行人姿态分析模型,智能分析判断出行人是否有快速运动、打架斗殴等异常个体和群体行为,及时向后台发出预警信息。
  • 剧烈挥手求救识别”技术,是利用深度学习人体姿态识别技术,精准识别人员向摄像头的剧烈挥手动作,当人员遇到不法侵害向摄像头剧烈挥手时,可以实时预警提醒后台人员。
  • 外观线索识别技术”,在茫茫人海中搜索一个人可以像百度查找一篇新闻那样容易。有了这个技术,可以跟踪犯罪嫌疑人到天涯海角,让不法分子再也无处遁形!而对于一些焦急寻找走失儿童的父母亲,或许将是一大福音。
    这套“行人搜索系统”的原理是,利用某一监控下的行人图像,可以在其它不同场景、不同光线、不同视角下的视频中准确搜索出该行人,并勾勒出其行动轨迹,搜索准确率可以达到90%。
  • 外观线索识别技术

    -“人员结构化智能分析”,通过图片处理性能达到20张/秒、视频处理性能最高达40路1080P的结构化服务器,能准确识别人脸、衣服颜色、出行姿态等等信息。将所有行人变成一个流动的“大数据库”,便于警方实现人员属性预警和人员属性搜索,进行更高层次的分析决策。

  • 携带物体识别技术”主要针对某些特定场所的安全监管需求,打造深度学习携带物体识别系统,当有人携带敏感物体时,系统会及时预警。

Flutter

JAVA

Gson,FastJson,Jackson,Json-lib不知道用哪个?看看性能对比
框架基于Maven构建,拆分成多个子模块,层次结构清晰。可用于所有Web应用,如企业后台管理系统、OA系统、CMS、CRM等。
框架本身集成了最新的 Flowable工作流引擎 https://www.flowable.org/ ,内置了流程流程设计器moduler,有完整的流程管理模块,可以轻松实现流程的在线设计、部署,流程发起、流程流转跟踪等一系列OA办公业务。
框架主模块包含:系统管理、流程管理、在线办公、文件管理、代码生成。系统管理子模块–用户管理、机构管理、区域管理、菜单管理、角色管理、字典管理、日志查询、连接池监视,实现权限精细控制,支持跨部门、跨公司数据权限授权。
框架支持前后端基础代码自动生成,免去重复劳动。

数据库

度 DBMS:PostgreSQL

PostgreSQL 已经连续两年赢得了“年度数据库”冠军称号。PostgreSQL 于 1989 年首次发布,今年恰好年满30岁,正处于人气高峰期,拥有一个非常活跃的社区并且没有出现丝毫“衰老”的迹象。

我们也可以看到,PostgreSQL 因其稳定性和强大的功能集而备受青睐,已成为众多开发者的首选数据库。PostgreSQL 以各种方式很好地满足了现代 DBMS 的要求。基于其坚实的 RDBMS 实现,它通过支持 JSON 数据类型和运算符扩展了其范围,从而为原本计划转向使用“文档存储”的项目提供了一个更有吸引力的选择。最近,在其发布的最新版本中,它专注于进一步提升分布式数据库的性能和对其的支持,以满足大数据场景的要求。

PostgreSQL 在 DBMS 市场中体现其成熟程度的一个强有力迹象是,DB-Engines 数据库排名中使用 PostgreSQL 作为基础技术的各种数据库管理系统。如果这些系统在其基础之上提供了重要的 DBMS 功能,我们将这些系统列为单独的条目。这些系统包括 Greenplum, EnterpriseDB, TimescaleDB, Citus 等。

Web服务端

GO

fileboy,文件变更监听通知系统,使用 Go 编写。
适用于 Hot Reload (典型的如开发go项目,无需每次手动执行 go build;又比如前端 node 打包) 或者 系统监控的场景。
v1.5 版本更新日志:
  • 增加 http 通知
  • 增加 callUrl 参数
  • 优化 command 稳定性
  • 增加 command -> delayMillSecond 参数
  • 优化 文案
  • 增加 在指定时间内堆叠的任务自动丢弃
  • 增加 version 信息
  • 优化 代码逻辑
GF(Go Frame)是一款模块化、松耦合、轻量级、高性能的Go应用开发框架。支持热重启、热更新、多域名、多端口、多服务、HTTP/HTTPS、动态路由等特性 ,并提供了Web服务开发的系列核心组件,如:Router、Cookie、Session、服务注册、配置管理、模板引擎、数据校验、分页管理、数据库ORM等等等等, 并且提供了数十个内置核心开发模块集,如:缓存、日志、时间、命令行、二进制、文件锁、内存锁、对象池、连接池、数据编码、进程管理、进程通信、文件监控、定时任务、TCP/UDP组件、 并发安全容器等等等等等等。

Docker

TOOL

mt管理器3.0永久会员破解版是专为安卓手机打造的文件管理工具,支持对所有文件进行处理,mt文件管理器还自带了编辑器、播放器、图片预览等功能,总之非常强大,赶快下载体验吧!
mt管理器3.0破解版功能
  • 像 WinRAR 那样打开 ZIP 格式文件,可以对 ZIP 内的文件进行删除、重命名、移动,添加/替换外部文件到 ZIP 中,无需解压后再重新打包,同时支持单独解压 ZIP 内的部分文件。
  • 文件复制、移动、创建软链接、重命名、删除、创建文件(夹),文件批量操作。获取 Root 权限后可访问系统目录,挂载文件系统为读写,修改文件权限和所有者。
  • 拥有图片查看、音乐播放、字体预览、执行脚本、文本对比等功能,在侧拉栏中可方便地查看存储设备、FTP连接、书签、后台、工具等。
  • 自带强大的文本编辑器,可以流畅编辑大文本文件,支持设置是否显示行号、开关自动换行、双指缩放字体大小、自动识别编码、代码语法高亮、自动缩进、正则搜索替换。
  • APK 编辑功能,主要有 DEX 编辑,ARSC 编辑,XML 编辑,APK 签名、APK 优化、APK 共存、去除签名校验、RES 资源混淆、RES 反资源混淆、翻译模式等。

3 of 4 in the series: 分享每一周

理解Flutter widget的生命周期

前言:

生命周期是一个组件加载到卸载的整个周期,熟悉生命周期可以让我们在合适的时机做该做的事情, 
flutter中的State生命周期和android以及React Native的生命周期类似。

生命周期的流程图:

大致可以分为3个阶段:
  • 初始化

  • 状态变化

  • 组件移除

初始化

State初始化时会依次执行 : 构造函数 > initState > didChangeDependencies > Widget build , 此时页面加载完成。
然后我们看一下每个函数的意义:

构造函数

调用次数:1次
这个函数严格意义上来讲不属于生命周期的一部分,因为这个时候State的widget属性为空,无法在构造函数中访问widget的属性 。但是构造函数必然是要第一个调用的。可以在这一部分接收前一个页面传递过来的数据。

initState

Called when this object is inserted into the tree.
调用次数:1次
当插入渲染树的时候调用,这个函数在生命周期中只调用一次。这里可以做一些初始化工作,比如初始化State的变量。

didChangeDependencies

Called when a dependency of this [State] object changes.
初始化时,在initState()之后立刻调用
当依赖的InheritedWidget rebuild,会触发此接口被调用
这个函数会紧跟在initState之后调用,并且可以调用BuildContext.inheritFromWidgetOfExactType,那么BuildContext.inheritFromWidgetOfExactType的使用场景是什么呢?最经典的应用场景是
new DefaultTabController(length: 3, child: new TabBar(
      tabs: [ "主页","订单","我的" ]
      .map( (data)=>new Text(data) ).toList(),
TabBar本来需要定义一个TabController,但是在外面套一层DefaultTabController就不需要定义TabContrller了,看下源码:
@override
  void didChangeDependencies() {
    super.didChangeDependencies();
    _updateTabController();
    _initIndicatorPainter();
  }

void _updateTabController() {
    final TabController newController = widget.controller ?? DefaultTabController.of(context);
    ...
    }
注意到这里DefaultTabController.of(context)
static TabController of(BuildContext context) {
    final _TabControllerScope scope = context.inheritFromWidgetOfExactType(_TabControllerScope);
    return scope?.controller;
  }
实际上就是调用BuildContext.inheritFromWidgetOfExactType,也就说在didChangeDependencies中,可以跨组件拿到数据。

运行时

build

调用次数:多次
初始化之后开始绘制界面,当setState触发的时候会再次被调用

didUpdateWidget

Called whenever the widget configuration changes.
祖先节点rebuild widget时调用 .当组件的状态改变的时候就会调用didUpdateWidget.
理论上setState的时候会调用,但我实际操作的时候发现只是做setState的操作的时候没有调用这个方法。而在我改变代码hot reload时候会调用 didUpdateWidget 并执行 build…
实际上这里flutter框架会创建一个新的Widget,绑定本State,并在这个函数中传递老的Widget。
这个函数一般用于比较新、老Widget,看看哪些属性改变了,并对State做一些调整。
需要注意的是,涉及到controller的变更,需要在这个函数中移除老的controller的监听,并创建新controller的监听。

组件移除

组件移除,例如页面销毁的时候会依次执行:deactivate > dispose

deactivate

Called when this object is removed from the tree.
在dispose之前,会调用这个函数。实测在组件课件状态变化的时候会调用,当组件卸载时也会先一步dispose调用。

dispose

Called when this object is removed from the tree permanently.
调用次数:1次
一旦到这个阶段,组件就要被销毁了,这个函数一般会移除监听,清理环境。

reassemble

hot reload调用
名称
状态
initState
插入渲染树时调用,只调用一次
didChangeDependencies
state依赖的对象发生变化时调用
didUpdateWidget
组件状态改变时候调用,可能会调用多次
build
构建Widget时调用
deactivate
当移除渲染树的时候调用
dispose
组件即将销毁时调用

实际场景

假设我们从A页面跳转到B页面, 那么A,B页面的生命周期会是怎样的呢?
B页面进入初始化状态,依次执行4个函数:构造函数 > initState > didChangeDependencies > Widget build , 此时页面加载完成,进入运行态。
此时A页面依次执行deactivate > build函数。注意 此时A页面并未卸载。
然后我们假设B页面只有一个按钮,点击B页面中的按钮,改变按钮的文字,会执行widget的build方法 ,(理论上也应该执行didUpdateWidget,但我这里没有)。
这时,我们点击返回键从B页面返回到A页面。
A页面重新显示,B页面开始卸载。
那么A先执行deactivate > build , 然后B页面依次执行:deactivate > dispose 。
此时A页面进入运行态,B页面移除。
本次示例B页面代码:
 /*
 * Created by 李卓原 on 2018/9/13.
 * email: zhuoyuan93@gmail.com
 *
 */

import 'package:flutter/material.dart';

class NewsDetailPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => NewsDetailState();
}

class NewsDetailState extends State<NewsDetailPage> {
  int text = 1;

  NewsDetailState() {
    print('构造函数');
  }

  @override
  void initState() {
    print('init state');
    super.initState();
  }

  @override
  void didChangeDependencies() {
    print('didChangeDependencies');
    super.didChangeDependencies();
  }

  @override
  Widget build(BuildContext context) {
    print('widget build');

    return Scaffold(
      body: Center(
        child: _loading(),
      ),
      appBar: AppBar(
        title: Text('咨询详情'),
      ),
    );
  }

  @override
  void didUpdateWidget(NewsDetailPage oldWidget) {
    print('组件状态改变:didUpdateWidget');
    super.didUpdateWidget(oldWidget);
  }

  @override
  void deactivate() {
    print('移除时:deactivate');
    super.deactivate();
  }

  @override
  void dispose() {
    print('移除时:dispose');
    super.dispose();
  }

  //预加载布局
  Widget _loading() {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        CircularProgressIndicator(
          strokeWidth: 1.0,
        ),
        Container(
          child: Text("正在加载"),
          margin: EdgeInsets.only(top: 10.0),
        )
      ],
    );
  }
}

Tips:

下面内容来自咸鱼技术团队.
当ListView中的item滚动出可显示区域的时候,item会被从树中remove掉,此item子树中所有的state都会被dispose,state记录的数据都会销毁,item滚动回可显示区域时,会重新创建全新的state、element、renderobject
使用hot reload功能时,要特别注意state实例是没有重新创建的,如果该state中存在一下复杂的资源更新需要重新加载才能生效,那么需要在reassemble()添加处理,不然当你使用hot reload时候可能会出现一些意想不到的结果,例如,要将显示本地文件的内容到屏幕上,当你开发过程中,替换了文件中的内容,但是hot reload没有触发重新读取文件内容,页面显示还是原来的旧内容.
idChangeDependencies有两种情况会被调用。
创建时候在initState 之后被调用
在依赖的InheritedWidget发生变化的时候会被调用
正常的退出流程中会执行deactivate然后执行dispose。但是也会出现deactivate以后不执行dispose,直接加入树中的另一个节点的情况。
这里的状态改变包括两种可能:
1.通过setState内容改变
2.父节点的state状态改变,导致孩子节点的同步变化。

App生命周期

需要指出的是如果想要知道App的生命周期,那么需要通过WidgetsBindingObserver的didChangeAppLifecycleState 来获取。通过该接口可以获取是生命周期在AppLifecycleState类中。常用状态包含如下几个:
名称
状态
resumed
可见并能响应用户的输入
inactive
处在并不活动状态,无法处理用户响应
paused
不可见并不能响应用户的输入,但是在后台继续活动中
一个实际场景中的例子:
在不考虑suspending的情况下:
从后台切入前台生命周期变化如下: AppLifecycleState.inactive->AppLifecycleState.resumed;
从前台压后台生命周期变化如下: AppLifecycleState.inactive->AppLifecycleState.paused;

本文主要梳理一下StatefulWidget和StatelessWidget的生命周期

微组件

StatelessWidget

  1. 接收外部数据
  2. 执行部件构造方法
  3. 传入数据改变时会重新渲染UI

StatefulWidget

  1. 接收外部数据
  2. 执行部件构造方法和状态初始化方法
  3. 传入数据和 本类数据改变时都会重新渲染UI
这用到之前写的一个例子01_widget_basic
第一次运行项目

  1. ProductsManager部件初始化
  2. 创建ProductsManagerState
  3. 调用ProductsManagerState中的initState方法
  4. ProductsManagerState渲染
  5. Products部件初始化
  6. Products渲染
    当点击add product按钮数据发生改变时
    1.数据_products发生了变化 通过setState方法通知数据发生了改变 ProductsManagerState build方法被调用
  7. 而Products进行了重新构造,也就是说当外部数据变化时 Products中的 _products 直接被替换成传入的新数据而不是在修改原有数据
flutter拥有类似于react-native的状态机刷新机制,得益于分离出了StatelessWidget和StatefulWidget,资源分配更加合理的了,代码思路也清晰很多.
lutter中的视图Widget像Android中的Activity一样存在生命周期,生命周期的回调函数体都在State中。


组件State的生命周期整理:

创建阶段

Log所示:
image.png

Widget状态改变

操作:横竖屏切换
Log所示:
其他生命周期并没有执行
竖屏切换到横屏执行2次
横屏切换到竖屏执行2次
image.png

App切后台,再切回来

Log所示:
image.png

销毁阶段

Log所示:
image.png
流程如图:
image.png

import 'package:flutter/material.dart';

class LifecycleAppPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return new _LifecycleAppPageState('构造函数');
  }
}

class _LifecycleAppPageState extends State<LifecycleAppPage>
    with WidgetsBindingObserver {
  String str;

  int count = 0;

  _LifecycleAppPageState(this.str);

  @override
  void initState() {
    print(str);
    print('initState');
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void didChangeDependencies() {
    print('didChangeDependencies');
    super.didChangeDependencies();
  }

  @override
  void didUpdateWidget(LifecycleAppPage oldWidget) {
    print('didUpdateWidget');
    super.didUpdateWidget(oldWidget);
  }

  @override
  void deactivate() {
    print('deactivate');
    super.deactivate();
  }

  @override
  void dispose() {
    print('dispose');
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    switch (state) {
      case AppLifecycleState.inactive:
        print('AppLifecycleState.inactive');
        break;
      case AppLifecycleState.paused:
        print('AppLifecycleState.paused');
        break;
      case AppLifecycleState.resumed:
        print('AppLifecycleState.resumed');
        break;
      case AppLifecycleState.suspending:
        print('AppLifecycleState.suspending');
        break;
    }

    super.didChangeAppLifecycleState(state);
  }

  @override
  Widget build(BuildContext context) {
    print('build');
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('lifecycle 学习'),
        centerTitle: true,
      ),
      body: new OrientationBuilder(
        builder: (context, orientation) {
          return new Center(
            child: new Text(
              '当前计数值:$count',
              style: new TextStyle(
                  color: orientation == Orientation.portrait
                      ? Colors.blue
                      : Colors.red),
            ),
          );
        },
      ),
      floatingActionButton: new FloatingActionButton(
          child: new Text('click'),
          onPressed: () {
            count++;
            setState(() {});
          }),
    );
  }
}

class LifecyclePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return new Scaffold(
      body: new LifecycleAppPage(),
    );
  }
}


6 of 7 in the series: Fltter移动开发相关

超声工作站

每周学习第一期 (2018-11-26)

新闻

三农相关

环保相关

IT相关

常用软件

技术文章资料

RPC (Remote Procedure Call)即远程过程调用,是分布式系统常见的一种通信方法,已经有 40 多年历史。当两个物理分离的子系统需要建立逻辑上的关联时,RPC 是牵线搭桥的常见技术手段之一。除 RPC 之外,常见的多系统数据交互方案还有分布式消息队列、HTTP 请求调用、数据库和分布式缓存等。

Taro 是什么?

Taro 是由凹凸实验室打造的一套遵循 React 语法规范的多端统一开发框架。
现如今市面上端的形态多种多样,Web、App 端(React Native)、微信小程序等各种端大行其道,当业务要求同时在不同的端都要求有所表现的时候,针对不同的端去编写多套代码的成本显然非常高,这时候只编写一套代码就能够适配到多端的能力就显得极为需要。
使用 Taro,我们可以只书写一套代码,再通过 Taro 的编译工具,将源代码分别编译出可以在不同端(微信小程序、H5、App 端等)运行的代码。同时 Taro 还提供开箱即用的语法检测和自动补全等功能,有效地提升了开发体验和开发效率
uni-app是一个使用 Vue.js 开发跨平台应用的前端框架,开发者编写一套代码,可编译到iOS、Android、H5、小程序等多个平台。
pring Boot通过提供开箱即用的默认依赖或者转换来补充Spring REST支持。在Spring Boot中编写RESTful服务与SpringMVC没有什么不同。总而言之,基于Spring Boot的REST服务与基于Spring的REST服务完全相同,只是在我们引导底层应用程序的方式上有所不同。
1.REST简短介绍
REST代表Representational State Transfer. 是一种架构风格,设计风格而不是标准,可用于设计Web服务,可以从各种客户端使用.
基于REST的基本设计,其是根据一组动词来控制的操作
使用java开发设计六大基本原则(摘自阿里巴巴java开发规范)

设计模式的六大原则:

总原则-开闭原则

对扩展开放,对修改封闭。在程序需要进行拓展的时候,不能去修改原有的代码,而是要扩展原有代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。

想要达到这样的效果,我们需要使用接口和抽象类等,后面的具体设计中我们会提到这点。

1、单一职责原则

不要存在多于一个导致类变更的原因,也就是说每个类应该实现单一的职责,否则就应该把类拆分。

2、里氏替换原则(Liskov Substitution Principle)

任何基类可以出现的地方,子类一定可以出现。里氏替换原则是继承复用的基石,只有当衍生类可以替换基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。

里氏代换原则是对“开-闭”原则的补充。实现“开闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。里氏替换原则中,子类对父类的方法尽量不要重写和重载。因为父类代表了定义好的结构,通过这个规范的接口与外界交互,子类不应该随便破坏它。

3、依赖倒转原则(Dependence Inversion Principle)

面向接口编程,依赖于抽象而不依赖于具体。写代码时用到具体类时,不与具体类交互,而与具体类的上层接口交互。

4、接口隔离原则(Interface Segregation Principle)

每个接口中不存在子类用不到却必须实现的方法,如果不然,就要将接口拆分。使用多个隔离的接口,比使用单个接口(多个接口方法集合到一个的接口)要好。

5、迪米特法则(最少知道原则)(Demeter Principle)

一个类对自己依赖的类知道的越少越好。无论被依赖的类多么复杂,都应该将逻辑封装在方法的内部,通过public方法提供给外部。这样当被依赖的类变化时,才能最小的影响该类。

最少知道原则的另一个表达方式是:只与直接的朋友通信。类之间只要有耦合关系,就叫朋友关系。耦合分为依赖、关联、聚合、组合等。我们称出现为成员变量、方法参数、方法返回值中的类为直接朋友。局部变量、临时变量则不是直接的朋友。我们要求陌生的类不要作为局部变量出现在类中。

6、合成复用原则(Composite Reuse Principle)

尽量首先使用合成/聚合的方式,而不是使用继承。
RedisPlus是为Redis可视化管理开发的一款开源免费的桌面客户端软件,支持Windows 、Linux、Mac三大系统平台,RedisPlus提供更加高效、方便、快捷的使用体验,有着更加现代化的用户界面风格。该软件支持单机、集群模式连接,同时还支持SSH(单机、集群)通道连接。RedisPlus致力于为大家提供一个高效的Redis可视化管理软件。
本文解决跨域中的 get、post、data、cookie 等这些问题
TIMO后台管理系统,基于SpringBoot 2 + Jpa + Thymeleaf + Shiro 开发的通用型后台管理,采用分模块的方式便于开发和维护,目前已开发的功能:权限管理、字典管理、日志记录、代码生成,可以直接作为一个后台管理系统的脚手架!
SpringBoot-Plus 是一个基于SpringBoot 2 的管理后台系统,包含了用户管理,组织机构管理,角色管理,功能点管理,菜单管理,权限分配,数据权限分配,代码生成,子系统生成,文档管理和预览等功能.不同于其他简单的开源后台管理系统,Plus具备适当的企业应用深度
springboot有提供AbstractRoutingDataSource#determineCurrentLookupKey抽象方法去指定数据源,我们要做的就是实现切换数据源的逻辑;通过AOP在调用数据库之前切换数据源;

Android相关

1.我是怎么破解一个答题微信小程序的

此文相关资料

android 自动化 Uiautomator 的插件

Chrome使用相关

C:\Users\{%user%}\AppData\Local\Google\Chrome\User Data\Default\Bookmarks

java相关

.Net相关


4 of 4 in the series: 分享每一周

TextField多行操作


new TextField(
  keyboardType: TextInputType.multiline,
  maxLines: whatever,

Continue reading

2 of 7 in the series: Fltter移动开发相关

sqflite操作相关

SQLite 插件 同时支持 iOS 和Android.
    • 支持事务和批处理
    • 版本开放自动管理
    • 增删改查助手
  • iOS 和 Android的后台线程中执行的DB操作

开始

在您的flutter项目中添加依赖项:
dependencies:
  ...
  sqflite: any

引用示例

Import sqflite.dart
import 'package:sqflite/sqflite.dart';

原始的Sql查询

执行原始SQL查询的示例代码
// Get a location using getDatabasesPath
var databasesPath = await getDatabasesPath();
String path = join(databasesPath, 'demo.db');

// Delete the database
await deleteDatabase(path);

// open the database
Database database = await openDatabase(path, version: 1,
    onCreate: (Database db, int version) async {
  // When creating the db, create the table
  await db.execute(
      'CREATE TABLE Test (id INTEGER PRIMARY KEY, name TEXT, value INTEGER, num REAL)');
});

// Insert some records in a transaction
await database.transaction((txn) async {
  int id1 = await txn.rawInsert(
      'INSERT INTO Test(name, value, num) VALUES("some name", 1234, 456.789)');
  print('inserted1: $id1');
  int id2 = await txn.rawInsert(
      'INSERT INTO Test(name, value, num) VALUES(?, ?, ?)',
      ['another name', 12345678, 3.1416]);
  print('inserted2: $id2');
});

// Update some record
int count = await database.rawUpdate(
    'UPDATE Test SET name = ?, VALUE = ? WHERE name = ?',
    ['updated name', '9876', 'some name']);
print('updated: $count');

// Get the records
List<Map> list = await database.rawQuery('SELECT * FROM Test');
List<Map> expectedList = [
  {'name': 'updated name', 'id': 1, 'value': 9876, 'num': 456.789},
  {'name': 'another name', 'id': 2, 'value': 12345678, 'num': 3.1416}
];
print(list);
print(expectedList);
assert(const DeepCollectionEquality().equals(list, expectedList));

// Count the records
count = Sqflite
    .firstIntValue(await database.rawQuery('SELECT COUNT(*) FROM Test'));
assert(count == 2);

// Delete a record
count = await database
    .rawDelete('DELETE FROM Test WHERE name = ?', ['another name']);
assert(count == 1);

// Close the database
await dat


SqlHelper(助手)

使用助手的示例
inal String tableTodo = 'todo';
final String columnId = '_id';
final String columnTitle = 'title';
final String columnDone = 'done';

class Todo {
  int id;
  String title;
  bool done;

  Map<String, dynamic> toMap() {
    var map = <String, dynamic>{
      columnTitle: title,
      columnDone: done == true ? 1 : 0
    };
    if (id != null) {
      map[columnId] = id;
    }
    return map;
  }

  Todo();

  Todo.fromMap(Map<String, dynamic> map) {
    id = map[columnId];
    title = map[columnTitle];
    done = map[columnDone] == 1;
  }
}

class TodoProvider {
  Database db;

  Future open(String path) async {
    db = await openDatabase(path, version: 1,
        onCreate: (Database db, int version) async {
      await db.execute('''
create table $tableTodo ( 
  $columnId integer primary key autoincrement, 
  $columnTitle text not null,
  $columnDone integer not null)
''');
    });
  }

  Future<Todo> insert(Todo todo) async {
    todo.id = await db.insert(tableTodo, todo.toMap());
    return todo;
  }

  Future<Todo> getTodo(int id) async {
    List<Map> maps = await db.query(tableTodo,
        columns: [columnId, columnDone, columnTitle],
        where: '$columnId = ?',
        whereArgs: [id]);
    if (maps.length > 0) {
      return Todo.fromMap(maps.first);
    }
    return null;
  }

  Future<int> delete(int id) async {
    return await db.delete(tableTodo, where: '$columnId = ?', whereArgs: [id]);
  }

  Future<int> update(Todo todo) async {
    return await db.update(tableTodo, todo.toMap(),
        where: '$columnId = ?', whereArgs: [todo.id]);
  }

  Future close() async => db.close();
}

Transaction

不要使用数据库,而只在事务中使用Transaction对象来访问数据库
await database.transaction((txn) async {
  // Ok
  await txn.execute('CREATE TABLE Test1 (id INTEGER PRIMARY KEY)');
  
  // DON'T  use the database object in a transaction
  // this will deadlock!
  await database.execute('CREATE TABLE Test2 (id INTEGER PRIMARY KEY)');
});

批处理支持

为了避免频繁的交互,可以使用Batch:
batch = db.batch();
batch.insert('Test', {'name': 'item'});
batch.update('Test', {'name': 'new_item'}, where: 'name = ?', whereArgs: ['item']);
batch.delete('Test', where: 'name = ?', whereArgs: ['item']);
results = await batch.commit();
获取每个操作的结果都会带来成本(插入的id和更新和删除的更改的数量),尤其是在执行额外SQL请求的Android上。如果不关心结果并担心消耗大量资源和性能,可以使用
await batch.commit(noResult: true);
警告,在事务期间,在提交事务之前不会提交批处理
wait database.transaction((txn) async {
  var batch = txn.batch();
  
  // ...
  
  // commit but the actual commit will happen when the transaction is commited
  // however the data is available in this transaction
  await batch.commit();
  
  //  ...
});
默认情况下,一遇到错误(通常恢复未提交的更改),批处理就停止。您可以忽略错误,即使碰到一个操作失败,也能运行和提交操作成功每个提交:
await batch.commit(continueOnError: true);

表和列名

一般来说,最好避免对实体名称使用SQLite关键字。如果使用下列名称中的任何一个:
"add","all","alter","and","as","autoincrement","between","case","check",
"collate","commit","constraint","create","default","deferrable","delete",
"distinct","drop","else","escape","except","exists","foreign","from",
"group","having","if","in","index","insert","intersect","into","is",
"isnull","join","limit","not","notnull","null","on","or","order",
"primary","references","select","set","table","then","to",
"transaction","union","unique","update","using","values","when","where"

助手会逃避这个名字,如。。
db.query('table')
以上这行代码将等同于手动在表名周围添加双引号(令人困惑的是,这里命名的表),等同于如下代码
db.rawQuery('SELECT * FROM "table"');
但是在任何其他原始语句(包括order.、where、group.)中,确保使用双引号正确地转义名称。例如,参见下面,列名组在列参数中没有转义,而是在where参数中转义
db.query('table', columns: ['group'], where: '"group" = ?', whereArgs: ['my_group']);

SQLite 支持的数据类型

Sqlite还没有对值进行有效性检查,因此请避免不支持的类型

DateTime

SQLite不支持DateTime类型。我个人将它们存储为int(.sSinceEpoch)或string(iso8601)

Bool

SQLite不支持bool类型。使用整数和0和1值。

INTEGER

    • Dart type: int
  • 取值范围: 从-2^63 到 2^63 – 1

REAL

  • Dart type: num

TEXT

  • Dart type: String

BLOB

    • Dart type: Uint8List
  • Dart type List<int> 是支持的,但是不推荐使用 慢速转换)

当前问题

    • Due to the way transaction works in SQLite (threads), concurrent read and write transaction are not supported. All calls are currently synchronized and transactions block are exclusive. I thought that a basic way to support concurrent access is to open a database multiple times but it only works on iOS as Android reuses the same database object. I also thought a native thread could be a potential future solution however on android accessing the database in another thread is blocked while in a transaction…
  • Currently INTEGER are limited to -2^63 to 2^63 – 1 (although Android supports bigger ones)
上述机翻
由于事务在SQLIT(线程)中的工作方式,不支持并发读写事务。所有调用当前都是同步的,事务块是独占的。我认为支持并发访问的基本方法是多次打开数据库,但是它只能在iOS上工作,因为Android重用了相同的数据库对象。我还认为本机线程可能是未来可能的解决方案,但是当android访问另一个线程中的数据库时,在事务中会阻塞……
目前INTEGER被限制在-2^63到2^63-1(尽管Android支持更大的)

更多

相关类库


by phoenix翻译,原文转自

1 of 7 in the series: Fltter移动开发相关

实体类自动生成工具的配置

1.实体类自动生成

a.在线实体类处自动生成

1).JsonToDartClass转换地址-1:

2).JsonToDartClass转换地址-2:

b.离线实体类自动生成工具

Formatter是开源的,项目地址;https://github.com/debuggerx01/JSONFormat4Flutter

2.使用工程自动生成代码

参考资料

操作步骤

    1. 工程依赖中加入依赖库
      dependencies: 
        cupertino_icons: ^0.1.2 
        fluttertoast: ^2.0.3
        json_annotation: ^1.2.0
      dev_dependencies:
        build_runner: ^0.10.1+1
        json_serializable: ^1.1.0
      
    1. 建立需要生成的实体类
      import 'package:json_annotation/json_annotation.dart';
      
      part 'User.g.dart';
      
      @JsonSerializable()
      class User {
        User(this.id,
            this.username,
           ...
       );
       
        String username; 
      。。。
        factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
      
        Map<String, dynamic> toJson() => _$UserToJson(this);
      
        // 命名构造函数
        User.empty();
      
      }
      
  1. 在控制台输入生成命令
    flutter packages pub run build_runner build
    

5 of 7 in the series: Fltter移动开发相关