Flutter 基础知识

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();