flutter入门

本文真对 Flutter 的技术特性,做了一些略全面的入门级的介绍,如果你听说过Flutter,想去了解它,但是又不想去翻厚厚的API,那么本文就是为你准备的。

随着纯客户端到Hybrid技术,到RN&Weex,再到如今的Flutter技术,客户端实现技术不断前进。 在之前的一个APP项目中,因为历史原因当时选择了weex,随着使用的不断深入,我们逐渐发现了weex的渲染性能问题已经成为一个隐患和瓶颈。 而Flutter技术的不断成熟和流行,Flutter的良好的跨平台性和高性能优点,不断吸引着我们。

(本文包含以下内容,阅读完需要约18分钟)

  • 1.Flutter是啥玩意儿?
  • 2.移动端跨平台技术对比
    2.1 H5+原生APP
    2.2 RN&Weex
    2.3 Flutter
  • 3.Dart语言
  • 4.环境配置
  • 5.Hello World
    5.1 创建项目
    5.2 项目结构
    5.3 启动模拟器
    5.4 启动项目APP
    5.5 简化版的Hello World
    5.6 给页面加上状态
    5.7 小结一下
  • 6.路由
    6.1 单个页面的跳转
    6.2 更多页面跳转使用路由表
    6.3 路由传参
  • 7.widget
    7.1 Text
    7.2 Button
    7.3 Container
    7.4 Image
  • 8.布局
    8.1 Row & Column & Center 行列轴布局
    8.2 Align 角定位布局
    8.3 Stack & Positioned 绝对定位
    8.4 Flex & Expanded 流式布局
  • 9.动画
    9.1 简单动画:淡入淡出
    9.2 复杂一些的动画:放大缩小
  • 10.http请求
    10.1 HttpClient
    10.2 http
    10.3 Dio
  • 11.吐吐槽
    11.1 墙
    11.2 组件过度设计
    11.3 嵌套太多不适应
    11.4 布局修改会导致嵌套关系修改
    11.5 Dart语言升级
    11.6 不能热更新
  • 12.结语

1.Flutter是啥玩意儿?

Flutter是谷歌的移动UI框架,可以快速在iOS和Android上构建高质量的原生用户界面。

  • 具有 跨平台 开发特性,支持IOS、Android、Web三端。
  • 热重载 特性大大提高了开发效率
  • 自绘UI引擎 和编译成原生代码的方式,使得系统的运行时的 高性能 成为了可能
  • 使用 Dart语言 ,目前已经支持同时编译成Web端代码,

到底值不值得跟进Flutter技术呢? 还是看下Flutter,Weex,ReactNative的搜索指数对比,大概就知道这个行业趋势了。

image

蓝色是Flutter,可以看出上升势头非常强劲。 苦逼的前端就是这样,你不跟潮流,潮流就会把你抛弃。

2.移动端跨平台技术对比

为啥会有Flutter这种东西? 他的原理是什么? 他是怎么做到高性能的? 要明白这些问题,我们不得不从几种移动端跨平台技术的对比讲起。

2.1 H5+原生APP

技术门槛最低,接入速度最快,热更新最方便的,自然就是H5方式。APP中提供一个Webview使用H5页面的Http直连。APP和H5可以相互独立开发,JS使用Bridge与原生进行数据通信,显示界面依赖Webview的浏览器渲染。 但是带来的问题也很明显,因为是需要远程直连,那么初次打开H5页面,会有瞬间的白屏,并且Webview本身会有至少几十M的内存消耗。

当然,作为前端开发人员,在H5方式可以使用SPA单页面、懒加载、离线H5等各种前端优化手段进行性能优化,以使得H5的表现更接近原生。但是首次的瞬间白屏和内存,Bridge的通信效率低下,始终是被技术框架给局限住了。

2.2 RN&Weex

由于H5的那些弊端,爱折腾的前端工程师,祭出了RN、Weex两个大杀器, 使用原生去解析RN、Weex的显示配置,显示层、逻辑层都直接与原生数据通信。 因为抛弃了浏览器,自然渲染性能、执行性能都提升了一大截。

但是,每次遇到显示的变更,JS都还会通过Bridge和原生转一道再做渲染的调整,所以Bridge就最后成为了性能的瓶颈。在实际项目中,特别是做一些大量复杂动画处理的时候,由于渲染部分需要频繁通信,性能问题变得尤为突出。 有兴趣的同学可以去看看 BindingX ,里面有关于动画中数据通信效率低下导致动画帧率低下的详细说明。

2.3 Flutter

不得不佩服Google开发人员的想象力,为了达到极致性能,Flutter更前进了一步,Flutter代码编译完成以后,直接就是原生代码,并且使用自绘UI引擎原生方式做渲染。 Flutter依赖一个 Skia 2D图形化引擎 。Skia也是Android平台和Chrome的底层渲染引擎,所以性能方面完全不用担心。因为使用Dart做AOT编译成原生,自然也比使用解释性的JS在V8引擎中执行性能更快,并且因为去掉Bridge,没有了繁琐的数据通信和交互,性能就更前进了一步。

3.Dart语言

学习Flutter,得先了解Dart。Dart语言曾经雄心勃勃的要替换Javascript, 但是发布的时机正好遇到JS的飞速发展,于是就逐渐沉寂,直到配合Flutter的发布,才又重新焕发了生机。

在最近2019年9月的一次Google开发者大会中,伴随着Flutter1.9的发布,目前的 Dart也同时更新到了2.5版本 , 提供了机器学习和对C跨平台调用的能力。总体来说,Dart语法,对于前端同学,上手还是很容易的,风格很像。

关于Dart语法,请移步传送门: https://dart.dev/samples

4.环境配置

无论学什么新语言,首先都是环境配置。由于Flutter出自Google,所以有一定门槛,如果在公司内安装,你还需要一个方便的代理切换工具, 比如:Proxifier 。

安装教程,参照官网: https://flutter.dev/docs/get-started/install

Flutter支持多种编辑器如:Android Studio , XCode。 但是既然作为支持跨双端的开发,个人还是推荐使用VSCode。

VSCode安装完成后,需要安装Flutter插件,和Dart插件. 在扩展窗口里,搜索 Flutter ,和 Dart ,点击“Install”即可,非常方便。

如果安装不上去,记得开启下代理。

5.Hello World

作为一个伟大的程序员,第一行代码总是从Hello World开始。 _

5.1 创建项目:

方法1:直接使用命令创建:

flutter create projectname

方法2:使用VSCode创建:

View -> Command Palette -> Flutter:New Project 即可

注意请先打开代理,否则你的创建进度,会一直被卡住。

5.2 项目结构

将项目先拖入VSCode,看下目录结构。自动创建完成的项目中,我们看到已经自带了Android,IOS相关的运行环境。

入口主文件是main.dart. 可以打开来先熟悉下,暂时不了解没关系,后面再讲。

还有一个重要的文件是pubspec.yaml ,是项目的配置文件,这个后续也会做修改。

5.3 启动模拟器

点击VSCode右下角的模拟器,启动模拟器。(VSCode会自动找到Android环境、IOS环境下的模拟器,以及真机环境)

5.4 启动项目APP

选中Main.dart, 点击 Debug-> Start Debugging , 项目就会启动调试,并在模拟器里运行。

5.5 简化版的Hello World

讲道理,Flutter一上来就用StatefulWidget做一个自增的Demo,其实是对新手不太友好。 我还是喜欢循序渐进,先删掉那些复杂的自增逻辑,我们基于StatelessWidget 只做一个最简单的静态页面显示。(什么是StatefulWidget 和StatelessWidget?后面会说)

main.dart

import 'package:flutter/material.dart';void main() => runApp(MyApp());class MyApp extends StatelessWidget {// This widget is the root of your application.@overrideWidget build(BuildContext context) {return MaterialApp(title: 'Flutter Demo',home: MyHomePage(),);}
}class MyHomePage extends StatelessWidget{@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("我是Title"),),body: Center(child: Text('Hello World',)));}  
}

在上面的代码中,可以清楚看到,最简单的页面的层级关系:

MaterialApp -> MyHomePage -> Scaffold -> body -> Center -> Text

Scaffold是啥?他是Flutter的页面脚手架,你可以当HTML页面一样去理解,不同的是,他除了Body以外,还提供appBar顶部TitleBar、bottomNavigationBar底部导航栏等属性。

显示效果:

这是最简单的页面,没有交互,只有显示,但是实际业务场景中,是不太可能都是这种页面的,页面上的数据一般都是来自接口返回,然后再在页面上进行动态的渲染。 此时,就需要使用使用带状态的StatefulWidget了

5.6 给页面加上状态

给自己一个需求,按钮点击时,修改页面上显示的文字“Hello World” 变成“You Click Me”

import 'package:flutter/material.dart';void main() => runApp(MyApp());class MyApp extends StatelessWidget {// This widget is the root of your application.@overrideWidget build(BuildContext context) {return MaterialApp(title: 'Flutter Demo',home: MyHomePage(),);}
}class MyHomePage extends StatefulWidget{@overrideMyHomePageState createState() => MyHomePageState();
}class MyHomePageState extends State<MyHomePage>{var msg="Hello World"; //msg默认文字@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("我是Title"),),body: Center(child:Column(children:<Widget>[Text(msg), //根据变量值,显示文字FlatButton(color: Colors.blue,textColor: Colors.white,//点击按钮,修改msg的文字onPressed: () {setState(() {this.msg="You Click ME";});},child: Text("Click ME",style: TextStyle(fontSize: 20.0),),)])));}  }

执行效果:

上面最关键的一段代码就是这个:

onPressed: () {setState(() {this.msg="You Click ME";});},

相信写过小程序的同学,对这个 setState 还是很眼熟的 _

5.7 小结一下

StatelessWidget:无状态变更,UI静态固化的Widget, 页面渲染性能更高。

StatefulWidget:因状态变更可以导致UI变更的的Widget,涉及到数据渲染场景,都使用StatefulWidget。

为啥要分两个? StatelessWidget拥有的功能,StatefulWidget都有了啊?

答案只有一个: 性能、性能、性能

在StatefulWidget里,因为要维护状态,他的生命周期比StatelessWidget更复杂,每次执行setState,都会触发

window.scheduleFrame() 导致整个页面的widget被刷新,性能就会降低。

使用过小程序的同学在这点上应该有体会,在小程序的官方文档中,会强烈建议减少setData的使用频率,以避免性能的下降。 只不过flutter更是激进,推出了StatelessWidget,并直接在该Widget里砍掉了setState的使用。

页面结构关系如下:

6.路由

实际的项目,是有多个不同的页面的,页面之间的跳转,就要用到路由了。 我们增加一个list页面,点击Home页的“Click Me”按钮,跳转到列表页list。

6.1 单个页面的跳转

增加list.dart

import 'package:flutter/material.dart';class ListPage extends StatelessWidget {@overrideWidget build(BuildContext context) {//定义列表widget的listList<Widget> list=<Widget>[];//Demo数据定义var data=[{"id":1,"title":"测试数据AAA","subtitle":"ASDFASDFASDF"},{"id":2,"title":"测试数据bbb","subtitle":"ASDFASDFASDF"},{"id":3,"title":"测试数据ccc","subtitle":"ASDFASDFASDF"},{"id":4,"title":"测试数据eee","subtitle":"ASDFASDFASDF"},];//根据Demo数据,构造列表ListTile组件listfor (var item in data) {print(item["title"]);list.add( ListTile( title: Text(item["title"],style: TextStyle(fontSize: 18.0) ),subtitle: Text(item["subtitle"]),leading:  Icon( Icons.fastfood, color:Colors.orange ),trailing: Icon(Icons.keyboard_arrow_right)));}//返回整个页面return Scaffold(appBar: AppBar(title: Text("List Page"),),body: Center(child: ListView(children: list,)),);}
}

在main.dart增加list页面的引入

import 'list.dart';

修改Home页的按钮事件,增加Navigator.push跳转

FlatButton(color: Colors.blue,textColor: Colors.white,onPressed: () {    Navigator.push(context, MaterialPageRoute(builder:(context) {return  ListPage();}));},child: Text("Click ME",style: TextStyle(fontSize: 20.0) ),)

核心方法就是: Navigator.push(context,MaterialPageRoute)

跳转示例:

6.2 更多页面跳转使用路由表

在MaterialApp中,有一个属性是routes,我们可以对路由进行命名,这样跳转的时候,只需要使用对应的路由名字即可,如: Navigator.pushNamed(context, RouterName) 。点击两个不同的按钮,分别跳转到ListPage,和Page2去。

Main.dart修改一下如下:

import 'package:flutter/material.dart';
import 'list.dart';
import 'page2.dart';void main() => runApp(MyApp());class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return MaterialApp(title: 'Flutter Demo',//路由表定义routes:{"ListPage":(context)=> ListPage(),"Page2":(context)=> Page2(),},home: MyHomePage(),);}
}class MyHomePage extends StatefulWidget{@overrideMyHomePageState createState() => MyHomePageState();
}class MyHomePageState extends State<MyHomePage>{@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("我是Title"),),body: Center(child:Column(children:<Widget>[RaisedButton(child: Text("Clikc to ListPage" ),onPressed: () {//根据命名路由做跳转Navigator.pushNamed(context, "ListPage");},),RaisedButton(child: Text("Click to Page2" ),onPressed: () {//根据命名路由做跳转Navigator.pushNamed(context, "Page2");},)])));}  }

示例:

当我们有了路由以后,就可以开始在一个项目里用不同的页面,去学习不同的功能了。

6.3 路由传参

列表页跳转到详情页,需要路由传参,这个在flutter体系里,又是怎么做的呢?

首先,在main.dart里,增加详情页DedailPage的路由配置

//路由表定义routes:{"ListPage":(context)=> ListPage(),"Page2":(context)=> Page2(),"DetailPage":(context)=> DetailPage(), //增加详情页的路由配置},

并修改ListPage里ListTile的点击事件,增加路由跳转传参,这里是将整个item数据对象传递

ListTile( title: Text(item["title"],style: TextStyle(fontSize: 18.0) ),subtitle: Text(item["subtitle"]),leading:  Icon( Icons.fastfood, color:Colors.orange ),trailing: Icon(Icons.keyboard_arrow_right),onTap:(){//点击的时候,进行路由跳转传参Navigator.pushNamed(context, "DetailPage", arguments:item);},)

详情页DetailPage里,获取传参并显示

import 'package:flutter/material.dart';
class DetailPage extends StatelessWidget {@overrideWidget build(BuildContext context) {//获取路由传参final Map args = ModalRoute.of(context).settings.arguments;return Scaffold(appBar: AppBar(title: Text("Detail Page"),),body: new Column(children: <Widget>[Text("我是Detail页面"),Text("id:${args['id']}" ),Text("id:${args['title']}"),Text("id:${args['subtitle']}")],));}
}

Demo效果:

7.widget

Flutter提供了很多默认的组件,而每个组件的都继承自widget 。 在Flutter眼里: 一切都是widget 。 这句看起来是不是很熟悉? 还记得在webpack里,一切都是module吗? 类似的还有java的一切都是对象。貌似任何一个技术,最后都是用哲学作为指导思想。

widget,作为可视化的UI组件,包含了显示UI、功能交互两部分。大的widget,也可以由多个小的widget组合而成。

常用的widget组件:

7.1 Text

Demo:

Text("Hello world",style: TextStyle(fontSize: 50,fontWeight: FontWeight.bold,color:Color(0xFF0000ff))),

Text的样式,来自另一个widget:TextStyle。 而TextStyle里的color,又是另一个widget Color的实例。

如果用flutter的缩进的方法,看起来确实有点丑陋,习惯写CSS的前端同学,可以看看下面的风格:

Text( "Hello world", style: TextStyle( fontSize: 50,fontWeight: FontWeight.bold,color:Color(0xFF0000ff) ) )

写成一行,是不是就顺眼多了?这算前端恶习吗? _

7.2 Button

对于flutter来说,Button就提供了很多种,我们来看看他们的区别:

RaisedButton: 凸起的按钮

FlatButton:扁平化按钮

OutlineButton:带边框按钮

IconButton:带图标按钮

按钮测试页dart:

import 'package:flutter/material.dart';class ButtonPage extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("Button Page"),),body: Column(children: <Widget>[RaisedButton(child: Text("我是 RaiseButton" ),onPressed: () {},),FlatButton(child: Text("我是 FlatButton" ),color: Colors.blue,onPressed: () {},),OutlineButton(child: Text("我是 OutlineButton" ),textColor: Colors.blue,onPressed: () {},),IconButton(icon: Icon(Icons.add),onPressed: () {},)  ]));}
}

Demo:

项目中要用哪个,就各取所需吧~

7.3 Container

Container是非常常用的一个widget,他一般是用作一个容器。我们先来看看他的基础属性,顺便可以想想他像HTML里的啥?

基础属性:width,height,color,child

body: Center(child: Container(color: Colors.blue,width: 200,height: 200,child: Text("Hello Container ",style:TextStyle(fontSize: 20,color: Colors.white)),))

Padding

我们也可以不设置宽高,用 padding 在内部撑开增加留白:

Container(color: Colors.blue,padding: EdgeInsets.all(30),child: Text("Hello Container ",style:TextStyle(fontSize: 20,color: Colors.white)),)

Margin

我们还可以使用 margin ,在容器的外部撑开增加偏移量,

Container(color: Colors.blue,padding: EdgeInsets.all(30),margin: EdgeInsets.only(left: 150,top: 0,right: 0,bottom: 0),child: Text("Hello Container ",style:TextStyle(fontSize: 20,color: Colors.white)),)

Transform

我们还可以给这个矩形,使用tansform做一些变化,比如,旋转一个角度

Container(color: Colors.blue,padding: EdgeInsets.all(30),child: Text("Hello Container ",style:TextStyle(fontSize: 20,color: Colors.white)),transform: Matrix4.rotationZ(0.5))

看到这里,好多前端同学要说了,好熟悉啊。 对,他就是很像Html里的一个东西: DIV ,你确实可以对应的去加强理解。

7.4 Image

网络图片加载

使用NetworkImage,可以做网络图片的加载:

child:Image(image: NetworkImage("https://mat1.gtimg.com/pingjs/ext2020/qqindex2018/dist/img/qq_logo_2x.png"),width: 200.0,)

本地图片加载

加载本地图片,就稍微复杂一些,首先要把图片的路径配置,加入到之前说过的pubspec.yaml配置文件里去:

image

加载本地图片时使用AssetImage:

child:Image(image: AssetImage("assets/images/logo.png"),width: 200.0,)

也可以使用简写:

Image.asset("assets/images/logo.png",width:200.0)

flutter提供的组件很多,这里就不一一举例说明,有兴趣的还是建议大家去看API: https://api.flutter.dev/

8.布局

我们已经了解了这么多组件,那么怎么绘制一个完整的页面呢? 这就到了页面布局的部分了。

8.1 Row & Column & Center 行列轴布局

字面意义也很好理解,行布局、列布局、居中布局,这些布局对于Flutter来说,也都是一个个的widget。

区别在于,row、column 是有多个children的widget, 而Center是只有 1个child的 widget。

Row(children:<Widget>[]) Column(children:<Widget>[])    Center(child:Text("Hello"))
8.2 Align 角定位布局

我们常常在Container里,需要显示的内容在左上角,左下角,右上角,右下角。 在html时代,使用CSS可以很容易的实现,但是flutter里,必须依赖Align 这个定位的Widget

右下角定位示例:

child: Container(color: Colors.blue,width: 300,height: 200,child: Align(alignment: Alignment.bottomRight,child:Text("Hello Align ",style:TextStyle(fontSize: 20,color: Colors.white)),))

显示效果:

Alignment提供了多种定位供选择,还算是很贴心的。

8.3 Stack & Positioned 绝对定位

当然还有绝对定位的需求,这在css里,使用position:absolute就搞定了,但是在flutter里,需要借助stack+ positioned两个widget一起组合使用。

Stack: 支持元素堆叠

Positioned:支持绝对定位

child:Stack(children: <Widget>[Image.network("https://ossweb-img.qq.com/upload/adw/image/20191022/627bdf586e0de8a29d5a48b86700a790.jpeg"),Positioned(top: 20,right: 10,child:Image.asset("assets/images/logo.png",width:200.0))],)

8.4 Flex & Expanded 流式布局

Flex流式布局作为前端同学都熟悉,之前讲过的Row,Column,其实都是继承自Flex,也属于流式布局。

如果轴向不确定,使用Flex,通过修改 direction的值设定轴向
如果轴向已确定,使用Row,Column,布局更简洁,更有语义化

Flex测试页:

class FlexPage extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("Flex Page"),),body:  Flex(direction: Axis.horizontal,children: <Widget>[Container(width: 30,height: 100,color: Colors.blue,),Expanded(flex: 1,child: Container(height: 100.0,color: Colors.red,),),Expanded(flex: 1,child: Container(height: 100.0,color: Colors.green,),),],),);}
}

示例中,轴向横向排列,最左边一个固定宽度的Container,右边两个Expanded,各自占剩下的宽度的一半。

9.动画

Flutter既然说了,一切都是Widget,包括动画实现,也是一个Widget。 我们还是看一个示例

9.1 简单动画:淡入淡出:

使用flutter提供的现成的Widget:

import 'package:flutter/material.dart';class AnimatePage extends StatefulWidget {_AnimatePage  createState()=> _AnimatePage();
} class _AnimatePage extends State<AnimatePage> {bool _visible=true;@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("Animate Page"),),body: Center(child: Column(children: <Widget>[AnimatedOpacity(opacity: _visible ? 1.0:0.0,duration: Duration(milliseconds: 1000),child: Image.asset("assets/images/logo.png"),),RaisedButton(child: Text("显示隐藏"),onPressed: (){setState(() {_visible=!_visible;});},),],),)    );}
}

其中的AnimatedOpacity就是动画透明度变化的的Widget,而被透明度控制变化的Image则是AnimatedOpacity的子元素。这个和以往前端写动画的方式,就完全不一样了,需要改变一下思维方式。

Demo效果

9.2 复杂一些的动画:放大缩小

当写复杂一些动画的时候,没有对应的widget组件,就需要自己使用Animation,和AnimationController,以及Tween来组合。

Animation: 保存动画的值和状态

AnimationController: 控制动画,包含:启动forward()、停止stop()、反向播放reverse()等方法

Tween: 提供begin,end作为动画变化的取值范围

Curve:设置动画使用曲线变化,如非匀速动画,先加速,后减速等的设定。

动画示例:

class AnimatePage2 extends StatefulWidget {_AnimatePage  createState()=> _AnimatePage();
} class _AnimatePage extends State<AnimatePage2>  with SingleTickerProviderStateMixin {Animation<double> animation;AnimationController controller;initState() {super.initState();controller =  AnimationController(duration:  Duration(seconds: 3), vsync: this);//使用弹性曲线,数据变化从0到300animation = CurvedAnimation(parent: controller, curve: Curves.bounceIn);animation = Tween(begin: 0.0, end: 300.0).animate(animation)..addListener(() {setState(() {});});//启动动画(正向执行)controller.forward();}@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("Animate Page"),),body: Center(child: Image.asset("assets/images/logo.png",width: animation.value, height: animation.value),)  );   }dispose() {//路由销毁时需要释放动画资源controller.dispose();super.dispose();}}

很重要的一点, 在路由销毁的时候,需要释放动画资源,否则容易导致内存泄漏 。

显示Demo:

10.http请求

做业务逻辑,总离不开http请求,接下来,就来看下flutter的http请求是如何做的。

10.1 HttpClient

httpClient在 dart:io库中,不需要引入第三方库就可以使用,示例代码如下:

使用示例

import 'dart:convert';
import 'dart:io';Future _getByHttpClient() async{//接口地址const url="https://www.demo.com/api";//定义httpClientHttpClient client = new HttpClient();//定义requestHttpClientRequest request = await client.getUrl(Uri.parse(url));//定义reponseHttpClientResponse response = await request.close();//respinse返回的数据,是字符串String responseBody = await response.transform(utf8.decoder).join();//关闭httpClientclient.close();//字符串需要转化为JSONvar json= jsonDecode(responseBody);return json;}

总的看起来,代码还是挺繁琐的,使用起来并不方便。

10.2 http

这是Dart.dev提供的第三方类库,地址: https://pub.dev/packages/http

需要先在pubspec.yaml里添加类库应用

dependencies:flutter:sdk: flutterjson_annotation: ^2.0.0http: ^0.12.0+2

使用示例:

Future _getByDartHttp() async {// 接口地址const url="https://www.demo.com/api";//获取接口的返回值final response = await http.get(url);//接口的返回值转化为JSONvar json = jsonDecode(response.body); return json;
}

这种写法,比上面的httpClient简洁了许多。

Dio

国内使用最广泛的,还是flutterchina在github上提供的Dio第三方库,目前Star达到了5800多个。

官网地址: https://github.com/flutterchina/dio

使用Dio,因为是第三方库,所以同样要先在 pubspec.yaml 添加第三方库引用。

dependencies:flutter:sdk: flutterjson_annotation: ^2.0.0dio: 2.1.16

使用示例:

import 'package:dio/dio.dart';Future _getByDio() async{// 接口地址const url="https://www.demo.com/api";//定义 Dio实例Dio dio = new Dio();//获取dio返回的ResponseResponse response = await dio.get(url);//返回值转化为JSONvar json=jsonDecode(response.data);return json;
}

接口调用也是比httpclient简单很多,可能由于fluterchina在他的官方教程里,极力推荐这个dio库,所以目前这个第三方库的使用情况最为广泛。和Dart.dev的http不同的是,他需要new一个Dio的实例,在创建实例的时候,还可以传入更多的扩展配置参数。

BaseOptions options = new BaseOptions(baseUrl: "https://www.xx.com/api",connectTimeout: 5000,receiveTimeout: 3000,
);
Dio dio = new Dio(options);

11.吐吐槽

学习Flutter的过程中,其实还是有很多坎坷和需要吐槽的地方。

11.1 墙

因为有墙在,所以在配置flutter,或者下载flutter插件和第三方库的时候,需要墙内外来回切换。

11.2 组件过度设计

提供的各种widget组件很多,但是真正核心的组件、常用的组件,也就哪些。 比如Flex 和column、row的关系,比如,Tween 与IntTween,ColorTween,SizeTween等20多个Tween子类之间的关系,你需要花很大的精力,去看每个具体子类的实现差别。

11.3 嵌套太多不适应

因为嵌套层级很多,而且布局、动画、功能都在一起,第一次上手Flutter和Dart,这种嵌套关系让人很晕菜,这个只能去慢慢克服。 另外,多开发自定义的组件,可以让嵌套关系看起来清晰一些。

11.4 布局修改会导致嵌套关系修改

前端的html+css分离世界里,不改变嵌套关系,修改CSS就可以调整布局。 但是在Flutter里因为布局也是嵌套关系,这就导致必须去改变嵌套关系。 要让嵌套更简单变动影响更小,页面拆分成子组件变得尤为重要。

11.5 Dart语言升级

没错,语言升级也会导致学习的困扰,外面的资料新旧都有,比如有些是 new Text() ,有些直接是Text() ,新手上路会很晕菜。 其实这都是Dart语言升级导致的,记住Dart升级2.X以后,都不使用new了。感兴趣的可以自己去看下Dart的升级变更说明。

11.6 不能热更新

年中的时候,Google官方宣布flutter暂不官方支持热更新,但是闲鱼团队已经有了自己的热更新方案。 关于热更新,只能静观其变了。 性能、开发效率、热更新,总是要有取舍的。即使是闲鱼团队,热更新也是付出了一点点性能下降的代价的,这是你选择flutter的初衷吗?还是那句话:权衡得失。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/742502.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

24计算机考研调剂 | 东北石油大学

东北石油大学智能物探团队招生宣传 考研调剂招生信息 学校:东北石油大学 专业:工学->地质资源与地质工程->矿产普查与勘探 年级:2024 招生人数:2 招生状态:正在招生中 联系方式:********* (为保护个人隐私,联系方式仅限APP查看) 补充内容 团队介绍&#xff1a; …

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的血细胞智能检测与计数(深度学习模型+UI界面代码+训练数据集)

摘要&#xff1a;开发血细胞智能检测与计数系统对于疾病的预防、诊断和治疗具有关键作用。本篇博客详细介绍了如何运用深度学习构建一个血细胞智能检测与计数系统&#xff0c;并提供了完整的实现代码。该系统基于强大的YOLOv8算法&#xff0c;并对比了YOLOv7、YOLOv6、YOLOv5&a…

C++顺序结构实例

1.计算浮点数相除的余数 计算两个双精度浮点数a和b相除的余数,a和b都是双精度浮点数。这里的余数r的定义是: a=k * 吧+r,其中k是整数,0<=r<b。 输入 一行,包括两个双精度浮点数a和b 输出 一行,a➗b的余数 样例输入 73.263 0.9973 样例输出 0.4301 #i…

jdk17下载安装图文教程【超详细】

目录 一、下载JDK17 二、安装JDK17 三、配置环境变量 四、测试Java安装是否成功 一、下载JDK17 访问官网&#xff1a;Java Downloads | Oracle 二、安装JDK17 三、配置环境变量 右键点击我的电脑>属性>高级系统设置>环境变量 在【系统变量】中新建JAVA_HOME&…

记录西门子:SCL设置不同顺序

一台搅拌的设备&#xff0c;需要控制三种料的进料顺序和进料重量&#xff0c;顺序和重量可以随便设定&#xff0c;也可以是几十种料。触摸屏上面有A、B、C三种液体原料&#xff0c;需要设定三种液体原料重量&#xff0c;并设定序号。 假设如下面所示设定&#xff1a;那将先打开…

AI 技术:改变世界的力量

人工智能&#xff08;AI&#xff09;是当今科技领域最热门的话题之一&#xff0c;它已经成为推动社会进步和经济发展的重要力量。AI 技术的应用范围非常广泛&#xff0c;从智能手机、自动驾驶汽车到医疗保健、金融服务等领域&#xff0c;都可以看到 AI 的身影。 那么&#xff0…

【考研数学】打基础用张宇《30讲》还是武忠祥《基础篇》?

基础课不太可能所有的东西全都覆盖&#xff0c;还是先搭起一个知识框架&#xff0c;然后不断的填充和完善。 所以不必太过于在意少一些东西&#xff0c;我们不可能一口吃成胖子&#xff0c;基础知识肯定不会遗漏的&#xff0c;只可能一些技巧不到位。 从自己的情况考虑&#…

三、HarmonyOS 应用开发入门之运行Hello World

目录 1、课程对象 1.1、有移动端开发经验 1.2、无移动端开发经验 1.3、对 HarmonyOS 感兴趣 2、DevEco Studio 的使用 2.1、DevEco Studio 的关键特性 智能代码编辑 低代码开发 多段双向实时预览 多端模拟仿真 2.2、安装配置 DevEco Studio 2.2.1、官网开发工具下载地…

基于Springboot的面向智慧教育的实习实践系统设计与实现(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的面向智慧教育的实习实践系统设计与实现&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&…

《深入Linux内核架构》第2章 进程管理和调度 (1)

目录 前言 2.1 进程优先级 2.2 进程生命周期 2.3 进程表示 2.3.1 进程类型 2.3.2 命名空间 2.3.3 进程ID号 2.3.4 进程关系 2.4 进程管理相关的系统调用 2.4.1 进程复制 2.4.2 内核线程 2.4.3 启动新程序 2.4.4 退出进程 前言 本章内容太多&#xff0c;分为两篇博…

游戏开发中的坑之十三 Lut贴图相关问题

1.网上下载的或者游戏截帧得到的Lut贴图贴上之后可能效果如下&#xff0c;需要在PS里垂直方向反转一下贴图。 2.相关设置&#xff1a; &#xff08;1&#xff09;取消勾选sRGB&#xff1b; &#xff08;2&#xff09;像素为1024x32或者512x16&#xff1b; &#xff08;3&#…

【机器学习300问】36、什么是集成学习?

一、什么是集成学习&#xff1f; &#xff08;1&#xff09;它的出现是为了解决什么问题&#xff1f; 提高准确性&#xff1a;单个模型可能对某些数据敏感或者有概念偏见&#xff0c;而集成多个模型可以提高预测的准确性。让模型变稳定&#xff1a;一些模型&#xff0c;如决策…

酷开科技以消费者需求为导向冲刺OTT行业的星辰大海

通过大屏营销、互动营销等方式&#xff0c;提升品牌认知度和市场竞争力。酷开科技始终坚持以消费者的需求为导向&#xff0c;致力于为品牌方和消费者搭建高效、准确的沟通桥梁&#xff0c;开创OTT大屏营销新纪元。 伴随技术发展&#xff0c;智能电视已经从“尝鲜”变成了主流产…

.NET MAUI 社区工具包 2023 年亮点

作者&#xff1a;Kym Phillpotts 排版&#xff1a;Alan Wang 2023 年已经过去了&#xff0c;让我们花点时间回顾一下 .NET MAUI Community Toolkit 项目的历程以及展望接下来的发展。作为 .NET MAUI 的配套产品&#xff0c;该开源库为开发人员提供了一组丰富多样的控件、转换器…

Axure基础 各元件的作用及介绍

图像热区 增加按钮或者文本的点击区域&#xff0c;他是透明的&#xff0c;在预览时看不见。 动态面板 用来绘制一下带交互效果的元件&#xff0c;他是动态的&#xff0c;如轮播图&#xff0c;一个动态面板里可以有多个子面板&#xff0c;每一个子面板对应着不同的效果。 他…

【研发日记】,Matlab/Simulink开箱报告(十)——Requirements Toolbox

前言 见《开箱报告&#xff0c;Simulink Toolbox库模块使用指南&#xff08;五&#xff09;——S-Fuction模块(C MEX S-Function)》 见《开箱报告&#xff0c;Simulink Toolbox库模块使用指南&#xff08;六&#xff09;——S-Fuction模块&#xff08;TLC&#xff09;》 见《开…

JavaEE:网络编程

网络编程&#xff1a;通过代码完成基于网络的跨主机通信 跨主机通信方式&#xff1a; 1.TCP/IP网络 2.蓝牙通信 3.近场通信NFC 4.毫米波通信&#xff1a;功率高&#xff0c;带宽高&#xff0c;抗干扰能力差 其中TCP/IP网络是日常编程中最常涉及到的&#xff0c;最通用的跨主机通…

安卓六大布局

LinearLayout&#xff08;线性布局&#xff09; 1.简介 线性布局在开发中使用最多&#xff0c;具有垂直方向与水平方向的布局方式。LinearLayout 默认是垂直排列的&#xff0c;但是可以通过设置 android:orientation 属性来改变为水平排列。 2.常用属性 orientation&#xf…

Linux编程4.3 网络编程-数据封装

1、数据封装 2、Internet协议&#xff08;IP&#xff09; IP的主要目的是为数据输入/输出网络提供基本算法&#xff0c;为高层协议提供无连接的传送服务。这意味着在IP将数据递交给接收站点以前不在传输站点和接收站点之间建立对话&#xff08;虚拟链路&#xff09;。它只是封…

【网络工程师进阶之路】BFD技术

个人名片&#xff1a;&#x1faaa; &#x1f43c;作者简介&#xff1a;一名大三在校生&#xff0c;喜欢AI编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;落798. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&a…