Flutter 是谷歌的移动UI框架,可以快速在 iOS 和 Android 上构建高质量的原生用户界面。
一、Flutter 中的生命周期
Flutter 中的生命周期
- initState() 表示当前 State 将和一个 BuildContext 产生关联,但是此时BuildContext 没有完全装载完成,如果你需要在该方法中获取 BuildContext ,可以 new Future.delayed(const Duration(seconds: 0, (){//context}); 一下。
-
didChangeDependencies() 在 initState() 之后调用,当 State 对象的依赖关系发生变化时,该方法被调用,初始化时也会调用。
-
deactivate() 当 State 被暂时从视图树中移除时,会调用这个方法,同时页面切换时,也会调用。
-
dispose() Widget 销毁了,在调用这个方法之前,总会先调用 deactivate()。
-
didUpdateWidge 当 widget 状态发生变化时,会调用。
Flutter 中 runApp 启动入口其实是一个 WidgetsFlutterBinding ,它主要是通过 BindingBase 的子类 GestureBinding 、ServicesBinding 、 SchedulerBinding 、PaintingBinding 、SemanticsBinding 、 RendererBinding 、WidgetsBinding 等,通过 mixins 的组合而成的。
二、Flutter 中存在四大线程
Flutter 中存在四大线程,分别为 UI Runner、GPU Runner、IO Runner, Platform Runner (原生主线程) ,同时在 Flutter 中可以通过 isolate 或者 compute 执行真正的跨线程异步操作。
三、Dart 基础
- Dart 属于是强类型语言 ,但可以用 var 来声明变量,Dart 会自推导出数据类型,var 实际上是编译期的“语法糖”。dynamic 表示动态类型, 被编译后,实际是一个 object 类型,在编译期间不进行任何的类型检查,而是在运行期进行类型检查。
-
Dart 中 if 等语句只支持 bool 类型,switch 支持 String 类型。
-
Dart 中数组和 List 是一样的。
-
Dart 中,Runes 代表符号文字 , 是 UTF-32 编码的字符串, 用于如 Runes input = new Runes('\u{1f596} \u{1f44d}');
-
赋值操作符
比较有意思的赋值操作符有:
AA ?? "999" ///表示如果 AA 为空,返回999
AA ??= "999" ///表示如果 AA 为空,给 AA 设置成 999
AA ~/999 ///AA 对于 999 整除
-
可选方法参数
Dart 方法可以设置 参数默认值 和 指定名称 。
比如: getDetail(Sting userName, reposName, {branch = "master"}){} 方法,这里 branch 不设置的话,默认是 “master” 。参数类型 可以指定或者不指定。调用效果: getRepositoryDetailDao(“aaa", "bbbb", branch: "dev"); 。 -
作用域
Dart 没有关键词 public 、private 等修饰符,_ 下横向直接代表 private ,但是有 @protected 注解 。 -
构造方法
Dart 中的多构造方法,可以通过命名方法实现。
默认构造方法只能有一个,而通过 Model.empty() 方法可以创建一个空参数的类,其实方法名称随你喜欢,而变量初始化值时,只需要通过 this.name 在构造方法中指定即可:
class ModelA {
String name;
String tag;
//默认构造方法,赋值给name和tag
ModelA(this.name, this.tag);
//返回一个空的ModelA
ModelA.empty();
//返回一个设置了name的ModelA
ModelA.forName(this.name);
}
- getter setter 重写
Dart 中所有的基础类型、类等都继承 Object ,默认值是 NULL, 自带 getter 和 setter ,而如果是 final 或者 const 的话,那么它只有一个 getter 方法,Object 都支持 getter、setter 重写:
@override
Size get preferredSize {
return Size.fromHeight(kTabHeight + indicatorWeight);
}
-
Assert(断言)
assert 只在检查模式有效,在开发过程中,assert(unicorn == null); 只有条件为真才正常,否则直接抛出异常,一般用在开发过程中,某些地方不应该出现什么状态的判断。 -
类、接口、继承
Dart 中没有接口,类都可以作为接口,把某个类当做接口实现时,只需要使用 implements ,然后复写父类方法即可。
Dart 中支持 mixins ,按照出现顺序应该为extends 、 mixins 、implements 。
四、Dart 基础数据类型
Dart | Android | iOS |
---|---|---|
null | null | nil(NSNull when nested) | 0 |
bool | java.lang.Boolean | NSNumber numberWithBool: |
int | java.lang.Integer | NSNumber numberWithInt: |
int,if 32 bits not enough | java.lang.Long | NSNumber numberWithLong: |
int,if 64 bits not enough | java.math.BigInteger | |
double | java.lang.Double | NSNumber numberWithDouble: |
String | java.lang.String | NSString |
Uint8List | byte[] | |
Int32List | int[] | |
Int64List | long[] | |
Float64List | double[] | |
List | java.util.ArrayList | NSArray |
Map | java.util.HashMap | NSDictionary |
Dart 中 number 类型分为 int 和 double ,没有 float 类型。
五、Zone
Dart 中可通过 Zone 表示指定代码执行的环境,类似一个沙盒概念,在 Flutter 中 C++ 运行 Dart 也是在 _runMainZoned 内执行 runZoned 方法启动,而我们也可以通过 Zone ,在运行环境内捕获全局异常等信息:
runZoned(() {
runApp(FlutterReduxApp());
}, onError: (Object obj, StackTrace stack) {
print(obj);
print(stack);
});
同时可以给 runZoned 注册方法,在需要时执行回调,如下代码所示,这样的在一个 Zone 内任何地方,只要能获取 onData 这个 ZoneUnaryCallback,就都可以调用到 handleData
///最终需要处理的地方
handleData(result) {
print("VVVVVVVVVVVVVVVVVVVVVVVVVVV");
print(result);
}
///返回得到一个 ZoneUnaryCallback
var onData = Zone.current.registerUnaryCallback<dynamic, int>(handleData);
///执行 ZoneUnaryCallback 返回数据
Zone.current.runUnary(onData, 2);
异步逻辑可以通过 scheduleMicrotask 可以插入异步执行方法:
Zone.current.scheduleMicrotask((){
//todo something
});
六、十大特性
编程语言总是朝着轻便化前进, Dart 也不例外。
6.1 字符串插值(字符串运算+替换)
print('${3 + 2}') // '5'
print('${"word".toUpperCase()}') // 'WORD'
print('$myObject') // The value of myObject.toString()
6.2 ?? 和 ??= 运算符
”a ??= b“: 先判断变量 a 是否为 null,如果为 null 则将b的值赋予a,否则跳过;
”a ?? b“ 这里的a和b针对的是表达式, 当表达式a不为null, 返回a; 如果a为null, 返回b。其实 ?? 和 ??= 差不多, 只不过 ?? 第一个值为表达式,而 ??= 第一个值为变量。
“a ? b :c” 三元表达式
“?.” : 看下面的例子
int a; // Dart变量初始值为null,不为0或者其他值
a ??= 3;
print(a); // 3.
a ??= 5;
print(a); // a 的值仍然为 3.
print(1 ?? 3); // 打印 1.
print(null ?? 12); // 打印 12.
myObject?.someProperty
等价于
(myObject != null) ? myObject.someProperty : null
6.3 箭头函数(=>)
当函数的返回语句只有一句时,可以用箭头函数代替,算是 Dart 里面最常用的了
void main() {
void helloWorld() => print("hello world");
helloWorld();
/*
等价于
void helloWorld() {
print("hello world");
}
*/
}
6.4 级联器(..)
class Rectangle {
int width;
int height;
// 等价于 int area() => width * height;
int area() {
return this.width * this.height;
}
}
void main() {
// 初始化一个对象
Rectangle r = Rectangle()
..width = 10
..height = 20;
/*
等价于
Rectangle r = Rectangle();
r.width = 10;
r.height = 20;
*/
print(r.area()); // 200
print(r..area()); // Instance of 'Rectangle'
// 看不到东西,但实际上执行了area函数
Rectangle()
..width = 20
..height = 20
..area();
}
6.5 getter 和 setter 选择器
class MyClass {
int _aProperty = 0;
int get aProperty => _aProperty;
set aProperty(int value) {
if (value >= 0) {
_aProperty = value;
}
}
}
等价于
class MyClass2 {
int _aProperty = 0;
int getAProperty() {
return _aProperty;
}
void setAProperty(int value) {
if (value >= 0) {
_aProperty = value;
}
}
}
6.6 可选参数
// Dart有两种形式的可选参数,第一种是可选位置参数,另一种是可选命名参数(用得比较多)
- 位置参数: [String param1, String param2]
- 命名参数: {String param1, String param2}
两者选其一
// 必选参数
int sum(int a, int b) {
return a + b;
}
print(sum(1, 2)); // 3
// 可选位置参数
int sum(int a, int b, [int c]) {
if (c != null) {
return a + b + c;
}
return a + b;
}
print(sum(1, 2)); // 3
print(sum(1, 2, 3)); // 6
// 可选命名参数
int sum(int a, int b, {int c}) {
if (c != null) {
return a + b + c;
}
return a + b;
}
print(sum(1, 2)); // 3
print(sum(1, 2, c: 3)); // 6
6.7 构造器简便写法
class MyColor {
int red;
int green;
int blue;
MyColor(this.red, this.green, this.blue);
/* 等价于
MyColor() {
this.red = red;
this.green = green;
this.blue = blue;
} */
}
final color = MyColor(80, 80, 128);
6.8 Initializer lists
序列化和反序列化
class User {
String user;
String pwd;
User();
// fromJson构造器,用于赋初值(Initializer lists), 并对传入的值进行校验(这部分可省略)
User.fromJson(Map<String, dynamic> json):
assert(json['user'] != ""), assert(json['pwd'] != ""),
user = json['user'], pwd = json['pwd'];
/*
等价于
static User fromJson(Map<String, dynamic> json){
User u = new User();
u.user = json['user'];
u.pwd = json['pwd'];
return u;
}
*/
// 这个例子其实就是Dart中json数据的序列化和反序列化, fromJson是序列化,toJson是反序列化
Map<String, dynamic> toJson() => {
'user': user,
'pwd': pwd,
};
/*
等价于
Map<String, dynamic> toJson() {
var map = new Map<String, dynamic>();
map['user'] = user;
map['pwd'] = pwd;
return map;
}
};
*/
}
void main() {
Map<String, dynamic> testData = {'user': 'aa', 'pwd': 'bb'};
User u = User.fromJson(testData);
print(u); // Instance of 'User'
Map testDataR = u.toJson();
print(testDataR); // {user: aa, pwd: bb}
}
6.9 命名构造器(Named constructors)
命令构造器,官方文档只解释说“命名构造器的作用是为了让一个类有多个构造器”。我们可以通过"类名.自定义名" 来创建构造器, 如下面的 Point.origin(), Point.helloWorld(), 你想定义什么名字就什么名字,这才明白命名构造器的含义。
class Point {
num x, y;
Point({this.x, this.y}); // 与官方文档不同
Point.origin() {
x = 0;
y = 0;
}
Point.helloWorld() {
x = 1;
y = 1;
}
}
final myPoint1 = Point();
final myPoint2 = Point.origin();
print(myPoint1.x); // null
print(myPoint2.y); // 0
6.10 工厂构造器(Factory constructors)
Java的工厂模式
public interface Shape {
void draw();
}
public class Square implements Shape {
@Override
public void draw() {
System.out.println("Inside Square::draw() method.");
}
}
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Inside Circle::draw() method.");
}
}
public class ShapeFactory {
//使用 getShape 方法获取形状类型的对象
public Shape getShape(String shapeType){
if(shapeType == null){
return null;
}
if(shapeType.equalsIgnoreCase("circle")){
return new Circle();
} else if(shapeType.equalsIgnoreCase("square")){
return new Square();
}
return null;
}
}
public class FactoryPatternDemo {
public static void main(String[] args) {
ShapeFactory shapeFactory = new ShapeFactory();
//获取 Circle 的对象,并调用它的 draw 方法
Shape shape1 = shapeFactory.getShape("circle");
shape1.draw();
//获取 Square 的对象,并调用它的 draw 方法
Shape shape3 = shapeFactory.getShape("square");
shape3.draw();
}
}
Dart 的工厂模式
// 比Java的更简洁, 但思想不变,其中Shape.fromTypeName可以自定义为其他名字,比如Shape.fromType
class Square extends Shape {
@override
void draw() => print("Inside Square::draw() method.");
}
class Circle extends Shape {
void draw() => print("Inside Circle::draw() method.");
}
class Shape {
Shape();
void draw(){}
factory Shape.fromTypeName(String typeName) {
if (typeName == 'square') return Square();
if (typeName == 'circle') return Circle();
print('I don\'t recognize $typeName');
return null;
}
}
Shape shape = Shape();
shape.draw();
Shape square = Shape.fromTypeName('square');
square.draw();