Flutter&Dart安装学习笔记

Flutter&Dart安装学习笔记

Flutter安装

https://flutter.io/
https://flutter-io.cn/

在国内,不可避免的是翻墙问题,这里有两个问题需要处理:

  1. 下载很慢。可以使用GitHub(https://github.com/flutter/flutter)下载源代码安装。
  2. 更新问题。可以使用国内镜像站设置环境变量替代。https://flutter-io.cn/#section-keynotes

源代码安装

先准备好Git工具,然后找一个没有中文和空格的路径,clone一份。
git clone -b beta https://github.com/flutter/flutter

原则上,将flutter\bin添加到环境变量就可以直接运行flutter_console.bat进行安装配置了。

但是,因为墙的原因,如果更新不成功,可以按照如下方法进行:
设置环境变量:

PATH 添加D:\flutter\bin
新建 FLUTTER_STORAGE_BASE_URL = https://storage.flutter-io.cn
新建 PUB_HOSTED_URL = https://pub.flutter-io.cn

然后重启计算机,双击flutter_console.bat进行安装,如果有网络错误提示,多试几次。

注意:运行flutter doctor,工具自动检测缺少的组建,进行安装,一般在pub upgrade环节等待时间比较长甚至没反应,多等一会,失败了关掉再重试,确保出来命令行,到此才算是安装完成。

IDE配置

官方推荐使用VSCode或者Android Studio开发,我这里选择VSCode。(64位最新版 https://code.visualstudio.com/Download)

安装插件:Flutter Dart,重载后,查看->命令面板,输入 Flutter:Run Flutter Doctor,查看工具链问题。

[flutter] flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel beta, v0.9.4, on Microsoft Windows [Version 10.0.16299.15], locale zh-CN)
[X] Android toolchain - develop for Android devices
    X Unable to locate Android SDK.
      Install Android Studio from: https://developer.android.com/studio/index.html
      On first launch it will assist you in installing the Android SDK components.
      (or visit https://flutter.io/setup/#android-setup for detailed instructions).
      If Android SDK has been installed to a custom location, set $ANDROID_HOME to that location.
[X] Android Studio (not installed)
[√] VS Code, 64-bit edition (version 1.28.1)
[!] Connected devices
    ! No devices available

! Doctor found issues in 3 categories.
exit code 0

如上,缺少Android相关工具链。

下载Android Studio,然后通过Studio下载SDK。 (此处需要代理,自行解决。Android SDK下载也可以使用国内镜像,参考https://www.cnblogs.com/zhuyp1015/p/4558978.html)

其实,只要配好AndroidStudio,其他IDE都很好弄。核心时代理问题。
Android Studio和Idea都是一个框架开发的IDE,插件也由官方维护,比较建议真正开发使用,VSCode看代码还是不错的。

Dart语言学习

最基础的一个Demo

import "dart:io";

// 定义个方法。
printNumber(num aNumber) {
  stdout.writeln('The number is $aNumber.'); // 在控制台打印内容。
}

// 这是程序执行的入口。
main() {
  print('Demo1');
  var number = 42; // 定义并初始化一个变量。
  printNumber(number); // 调用一个方法。
}

重要的概念:

  • 所有变量都是对象,包含数字、方法、null,都继承于Object。
  • 尽量使用静态类型,而不是var,这样有利于静态分析工具分析代码,并不是强制的。
  • Dart运行前会解析代码。
  • Dart支持顶级方法(如main()),还支持在类中定义函数,还可以在方法中定义方法。
  • Dart支持顶级变量,以及类中变量。
  • Dart没有public\protected\private,但是(_)开头的表示在库内是私有的。
  • 某些时候,表达式expression和语句statement是有区别的。

基础内容

关键字:

abstract 1	continue	false	new	this
as 1	default	final	null	throw
assert	deferred 1	finally	operator 1	true
async 2	do	for	part 1	try
async* 2	dynamic 1	get 1	rethrow	typedef 1
await 2	else	if	return	var
break	enum	implements 1	set 1	void
case	export 1	import 1	static 1	while
catch	external 1	in	super	with
class	extends	is	switch	yield 2
const	factory 1	library 1	sync* 2	yield* 2

默认值:没有初始化的任何变量,默认都为null。

Final and const

  • 如果你以后不打算修改一个变量,使用 final 或者 const。
  • 一个 final 变量只能赋值一次;一个 const 变量是编译时常量。 (Const 变量同时也是 final 变量。)
  • 顶级的 final 变量或者类中的 final 变量在 第一次使用的时候初始化。
  • 注意: 实例变量可以为 final 但是不能是 const 。

Dart 内置支持下面这些类型:

  • numbers
  • strings
  • booleans
  • lists (也被称之为 arrays)
  • maps
  • runes (用于在字符串中表示 Unicode 字符)
  • symbols

整数:
num, 包含int和double
Dart 具有任意精度的整数。

// int
var x = 1;
var hex = 0xDEADBEEF;
var bigInt = 34653465834652437659238476592374958739845729;
// double
var y = 1.1;
var exponents = 1.42e5;

// 类型转换
// String -> int
var one = int.parse('1');
assert(one == 1);
// String -> double
var onePointOne = double.parse('1.1');
assert(onePointOne == 1.1);
// int -> String
String oneAsString = 1.toString();
assert(oneAsString == '1');
// double -> String
String piAsString = 3.14159.toStringAsFixed(2);
assert(piAsString == '3.14');

// 操作符
assert((3 << 1) == 6);  // 0011 << 1 == 0110
assert((3 >> 1) == 1);  // 0011 >> 1 == 0001
assert((3 | 4)  == 7);  // 0011 | 0100 == 0111

字符串:
Dart字符串是UTF-16编码,可以使用单引号或者双引号创建。
变量引用: $varname or ${varname}

通过三个单引号或者三个双引号,创建多行文本。通过r前缀创建原始raw字符串。

字符串字面量是编译时常量, 带有字符串插值的字符串定义,若干插值表达式引用的为编译时常量则其结果也是编译时常量。

// 声明
var s3 = 'It\'s easy to escape the string delimiter.';
var s4 = "It's even easier to use the other delimiter.";

// 引用和比较
var s = 'string interpolation';
assert('Dart has $s, which is very handy.' == 'Dart has string interpolation, ' + 'which is very handy.');
assert('That deserves all caps. ' + '${s.toUpperCase()} is very handy!' == 'That deserves all caps. ' + 'STRING INTERPOLATION is very handy!');

布尔值
Dart 有一个名字为 bool 的类型, 只有两个对象是布尔类型的:true 和 false 所创建的对象, 这两个对象也都是编译时常量。当 Dart 需要一个布尔值的时候,只有 true 对象才被认为是 true。 所有其他的值都是 flase。

列表
在 Dart 中数组就是 List 对象。所以 通常我们都称之为 lists。
Lists 的下标索引从 0 开始,第一个元素的索引是 0. list.length - 1 是最后一个元素的索引。

var list = [1, 2, 3];
assert(list.length == 3);
assert(list[1] == 2);

Map
键和值可以是任何类型的对象。每个 键 只出现一次, 而一个值则可以出现多次。Dart 通过 map 字面量 和 Map 类型支持 map。

var gifts = {
// Keys      Values
  'first' : 'partridge',
  'second': 'turtledoves',
  'fifth' : 'golden rings'
};

var nobleGases = {
// Keys  Values
  2 :   'helium',
  10:   'neon',
  18:   'argon',
};

var gifts = new Map();
gifts['first'] = 'partridge';
gifts['second'] = 'turtledoves';
gifts['fifth'] = 'golden rings';

// 不存在返回null
assert(gifts['fifth'] == null);

// insert
gifts['fourth'] = 'calling birds'; // Add a key-value pair

Runes:
runes代表使用UTF-32表示字符串,String部分属性可处理此种数据。
通常使用 \uXXXX 的方式来表示 Unicode code point, 这里的 XXXX 是4个 16 进制的数。 例如,心形符号 (♥) 是 \u2665。

main() {
  var clapping = '\u{1f44f}';
  print(clapping);
  print(clapping.codeUnits);
  print(clapping.runes.toList());

  Runes input = new Runes('\u2665  \u{1f605}  \u{1f60e}  \u{1f47b}  \u{1f596}  \u{1f44d}');
  print(new String.fromCharCodes(input));
}

Symbol:
一个 Symbol object 代表 Dart 程序中声明的操作符或者标识符。你也许从来不会用到 Symbol,但是该功能对于通过名字来引用标识符的情况 是非常有价值的,特别是混淆后的代码, 标识符的名字被混淆了,但是 Symbol 的名字不会改变。

使用 Symbol 字面量来获取标识符的 symbol 对象,也就是在标识符 前面添加一个 # 符号

方法:
Dart 是一个真正的面向对象语言,方法也是对象并且具有一种 类型, Function。 这意味着,方法可以赋值给变量,也可以当做其他方法的参数。 也可以把 Dart 类的实例当做方法来调用。

所有的函数都返回一个值。如果没有指定返回值,则 默认把语句 return null;

bool isNoble(int atomicNumber) {
  return _nobleGases[atomicNumber] != null;
}

// 对于只有一个表达式的方法,你可以选择 使用缩写语法来定义
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;

// 命名参数
enableFlags(bold: true, hidden: false); // 使用

enableFlags({bool bold, bool hidden}) { // 使用{}定义
  // ...
}

// 可选参数
assert(say('Bob', 'Howdy') == 'Bob says Howdy'); // 使用

String say(String from, String msg, [String device]) { // 使用[]定义
  var result = '$from says $msg';
  if (device != null) {
    result = '$result with a $device';
  }
  return result;
}

// 默认参数,一般配合上面的两种参数使用
void enableFlags({bool bold = false, bool hidden = false}) { // = 定义
  // ...
}
// bold will be true; hidden will be false.
enableFlags(bold: true);  // :使用

匿名方法:
有时候也被称为 lambda 或者 closure 闭包。

// 原型
([[Type] param1[, …]]) { 
  codeBlock; 
}; 

// demo
var list = ['apples', 'oranges', 'grapes', 'bananas', 'plums'];
//list.forEach((i) => print(list.indexOf(i).toString() + ': ' + i));
list.forEach((i) {
  print(list.indexOf(i).toString() + ': ' + i);
});

闭包
一个 闭包 是一个方法对象,不管该对象在何处被调用, 该对象都可以访问其作用域内 的变量。

/// Returns a function that adds [addBy] to the
/// function's argument.
Function makeAdder(num addBy) {
  return (num i) => addBy + i;
}

main() {
  // Create a function that adds 2.
  var add2 = makeAdder(2);

  // Create a function that adds 4.
  var add4 = makeAdder(4);

  assert(add2(3) == 5);
  assert(add4(3) == 7);
}

入口函数
每个应用都需要有个顶级的 main() 入口方法才能执行。 main() 方法的返回值为 void 并且有个可选的 List 参数。

void main() {
  querySelector("#sample_text_id")
    ..text = "Click me!"
    ..onClick.listen(reverseText);
}

级联操作符
级联操作符 (…) 可以在同一个对象上 连续调用多个函数以及访问成员变量。
使用级联操作符可以避免创建 临时变量, 并且写出来的代码看起来 更加流畅。

如入口函数中的代码,第一个方法 querySelector() 返回了一个 selector 对象。 后面的级联操作符都是调用这个对象的成员, 并忽略每个操作 所返回的值。

级联调用也可以嵌套

注意: 严格来说, 两个点的级联语法不是一个操作符。 只是一个 Dart 特殊语法。

final addressBook = (new AddressBookBuilder()
      ..name = 'jenny'
      ..email = 'jenny@example.com'
      ..phone = (new PhoneNumberBuilder()
            ..number = '415-555-0100'
            ..label = 'home')
          .build())
    .build();

操作符
除了常见的操作符,还有?? ?. as is ...

  • as 类型转换
  • is 判断类型,如果是,返回True。is!相反。
  • ?? 左侧如果是null,返回右侧,否则返回左侧。
  • ??= 右侧不是null则对左侧赋值,否则左侧不变。
  • ?. 和.作用类似,但是左侧为null时,返回null,否则正常执行。

异常:
所有的 Dart 异常是非检查异常。 方法不一定声明了他们所抛出的异常, 并且你不要求捕获任何异常

  • throw可以抛出任何类型的异常,包含普通对象。
  • catch可以捕获,on用来捕获特定的异常。
  • 函数 catch() 可以带有一个或者两个参数, 第一个参数为抛出的异常对象, 第二个为堆栈信息 (一个 StackTrace 对象)。
  • rethrow 可以 把捕获的异常给 重新抛出
  • finally 不管有没有出现异常都需要执行

Object
可以使用 Object 的 runtimeType 属性来判断实例 的类型,该属性 返回一个 Type 对象。
每个实例变量都会自动生成一个 getter 方法(隐含的)。 Non-final 实例变量还会自动生成一个 setter 方法。
注意:所有没有初始化的变量值都是 null。

Class
注意: 只有当名字冲突的时候才使用 this。否则的话, Dart 代码风格样式推荐忽略 this。

class Point {
  num x;
  num y;

  Point(num x, num y) {
    // There's a better way to do this, stay tuned.
    this.x = x;
    this.y = y;
  }
}

// 语法糖
class Point {
  num x;
  num y;

  // Syntactic sugar for setting x and y
  // before the constructor body runs.
  Point(this.x, this.y);
}

// 命名构造函数,不可继承
class Point {
  num x;
  num y;

  Point(this.x, this.y);

  // Named constructor
  Point.fromJson(Map json) {
    x = json['x'];
    y = json['y'];
  }
}

// 调用父类构造函数
class Person {
  String firstName;

  Person.fromJson(Map data) {
    print('in Person');
  }
}

class Employee extends Person {
  // Person does not have a default constructor;
  // you must call super.fromJson(data).
  Employee.fromJson(Map data) : super.fromJson(data) {
    print('in Employee');
  }
}

main() {
  var emp = new Employee.fromJson({});

  // Prints:
  // in Person
  // in Employee
  if (emp is Person) {
    // Type check
    emp.firstName = 'Bob1';
  }
  (emp as Person).firstName = 'Bob2';
}

Getter&Setter:

class Rectangle {
  num left;
  num top;
  num width;
  num height;

  Rectangle(this.left, this.top, this.width, this.height);

  // Define two calculated properties: right and bottom.
  num get right             => left + width;
      set right(num value)  => left = value - width;
  num get bottom            => top + height;
      set bottom(num value) => top = value - height;
}

main() {
  var rect = new Rectangle(3, 4, 20, 15);
  assert(rect.left == 3);
  rect.right = 12;
  assert(rect.left == -8);
}

接口:
如果你想 创建类 A 来支持 类 B 的 api,而不想继承 B 的实现, 则类 A 应该实现 B 的接口。
一个类可以通过 implements 关键字来实现一个或者多个接口, 并实现每个接口定义的 API。

// A person. The implicit interface contains greet().
class Person {
  // In the interface, but visible only in this library.
  final _name;

  // Not in the interface, since this is a constructor.
  Person(this._name);

  // In the interface.
  String greet(who) => 'Hello, $who. I am $_name.';
}

// An implementation of the Person interface.
class Imposter implements Person {
  // We have to define this, but we don't use it.
  final _name = "";

  String greet(who) => 'Hi $who. Do you know who I am?';
}

greetBob(Person person) => person.greet('bob');

main() {
  print(greetBob(new Person('kathy')));
  print(greetBob(new Imposter()));
}

// 多个接口
class Point implements Comparable, Location {
  // ...
}

枚举:
枚举类型中的每个值都有一个 index getter 函数, 该函数返回该值在枚举类型定义中的位置(从 0 开始)。
枚举的 values 常量可以返回 所有的枚举值。

enum Color {
  red,
  green,
  blue
}

assert(Color.red.index == 0);
assert(Color.green.index == 1);

List<Color> colors = Color.values;
assert(colors[2] == Color.blue);

使用 import 和 library 指令可以帮助你创建 模块化的可分享的代码。库不仅仅提供 API, 还是一个私有单元:以下划线 (_) 开头的标识符只有在库 内部可见。每个 Dart app 都是一个库, 即使没有使用 library 命令也是一个库。

import 必须参数为库 的 URI。 对于内置的库,URI 使用特殊的 dart: scheme。 对于其他的库,你可以使用文件系统路径或者 package: scheme。

如果你导入的两个库具有冲突的标识符, 则你可以使用库的前缀来区分。

import 'dart:io'; 
import 'package:mylib/mylib.dart';

import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;
// ...
Element element1 = new Element();           // Uses Element from lib1.
lib2.Element element2 = new lib2.Element(); // Uses Element from lib2.

// Import only foo.
import 'package:lib1/lib1.dart' show foo;

// Import all names EXCEPT foo.
import 'package:lib2/lib2.dart' hide foo;

// 延迟载入,当需要使用的时候,使用库标识符调用 loadLibrary() 函数来加载库,
// 多次调用 loadLibrary() 函数。 但是该库只是载入一次。
import 'package:deferred/hello.dart' deferred as hello;

异步支持
Dart 有一些语言特性来支持 异步编程。 最常见的特性是 async 方法和 await 表达式。

Dart 库中有很多返回 Future 或者 Stream 对象的方法。 这些方法是 异步的: 这些函数在设置完基本的操作 后就返回了, 而无需等待操作执行完成。 例如读取一个文件,在打开文件后就返回了。

有两种方式可以使用 Future 对象中的 数据:

  • 使用 async 和 await
  • 使用 Future API

同样,从 Stream 中获取数据也有两种 方式:

  • 使用 async 和一个 异步 for 循环 (await for)
  • 使用 Stream API
String lookUpVersionSync() => '1.0.0';
// 如果使用 async 关键字,则该方法 返回一个 Future,并且 认为该函数是一个耗时的操作。
Future<String> lookUpVersion() async => '1.0.0';

注意: 如果 await 无法正常使用,请确保是在一个 async 方法中。
比如,要在 main() 方法中使用 await, 则 main() 方法的函数体必须标记为 async:

main() async {
  checkVersion();
  print('In main: version is ${await lookUpVersion()}');
}

// for循环中使用异步
await for (variable declaration in expression) {
  // Executes each time the stream emits a value.
}

其他

可调用的类
如果 Dart 类实现了 call() 函数则 可以当做方法来调用。

class WannabeFunction {
  call(String a, String b, String c) => '$a $b $c!';
}

main() {
  var wf = new WannabeFunction();
  var out = wf("Hi","there,","gang");
  print('$out');
}

隔离(Isolates)
现代的浏览器以及移动浏览器都运行在多核 CPU 系统上。 要充分利用这些 CPU,开发者一般使用共享内存 数据来保证多线程的正确执行。然而, 多线程共享数据通常会导致很多潜在的问题,并导致代码运行出错。

所有的 Dart 代码在 isolates 中运行而不是线程。 每个 isolate 都有自己的堆内存,并且确保每个 isolate 的状态都不能被其他 isolate 访问。

Typedefs
在 Dart 语言中,方法也是对象。 使用 typedef, 或者 function-type alias 来为方法类型命名, 然后可以使用命名的方法。 当把方法类型赋值给一个变量的时候,typedef 保留类型信息。

// 类似callback函数,但是保留了运行时的推理能力
typedef int Compare(Object a, Object b); 

class SortedCollection {
  Compare compare;

  SortedCollection(this.compare);
}

 // Initial, broken implementation.
 int sort(Object a, Object b) => 0;

main() {
  SortedCollection coll = new SortedCollection(sort);
  assert(coll.compare is Function);
  assert(coll.compare is Compare);
}

元数据
使用元数据给你的代码添加其他额外信息。 元数据注解是以 @ 字符开头,后面是一个编译时 常量(例如 deprecated)或者 调用一个常量构造函数。

有三个注解所有的 Dart 代码都可以使用: @deprecated、 @override、 和 @proxy。

自定义元数据:

// define
library todo;

class todo {
  final String who;
  final String what;

  const todo(this.who, this.what);
}

// use
import 'todo.dart';

@todo('seth', 'make this do something')
void doSomething() {
  print('do something');
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值