推荐阅读
Flutter(二)Android集成Flutter项目并实现跳转到 Flutter 界面
Flutter练习项目,非常适合入门,下面是GitHub地址,欢迎star:
https://github.com/aiyangtianci/flutter_app
目录
一、Flutter 安装部署
Flutter 是 Google推出并开源的移动应用开发框架,主打跨平台、高保真、高性能。开发者可以通过 Dart语言开发 App,一套代码同时运行在 iOS 和 Android平台。 Flutter提供了丰富的组件、接口,开发者可以很快地为 Flutter添加 native扩展。同时 Flutter还使用 Native引擎渲染视图,一遍编写代码一遍查看运行效果,这无疑能为用户提供良好的体验。
由于Flutter会同时构建Android和IOS两个平台的发布包,所以Flutter同时依赖Android SDK和iOS SDK,在安装Flutter时也需要安装相应平台的构建工具和SDK。下面我们分别介绍一下Windows和macOS下的环境搭建。
(一)在Windows上搭建Flutter开发环境
1、去flutter官网下载其最新可用的安装包,下载地址:https://flutter.dev/docs/development/tools/sdk/releases,
打开后如图1-2所示:Beta渠道是稳定版本,Dev渠道是比较新的版本。
注意,Flutter的渠道版本会更新,请以Flutter官网为准。另外,在中国大陆地区,要想正常获取安装包列表或下载安装包,可能需要翻墙,读者也可以去Flutter github项目下去下载安装包,地址:https://github.com/flutter/flutter/releases 。
- 将安装包zip解压到你想安装Flutter SDK的路径(如:
C:\src\flutter
;注意,不要将flutter安装到需要一些高权限的路径如C:\Program Files\
)。 - 在Flutter安装目录的
flutter
文件下找到flutter_console.bat
,双击运行并启动flutter命令行,接下来,你就可以在Flutter命令行运行flutter命令了。
2、更新环境变量
在“用户环境变量”下检查是否有名为“Path”的条目:(类似添加Java环境变量,可以百度搜)
- 如果该条目存在, 追加 flutter\bin的全路径,使用 ; 作为分隔符。
- 如果该条目不存在,创建一个新用户变量 Path ,然后将
flutter\bin
的安装的全路径作为它的值。
重启Windows以应用此更改.
3、在Flutter命令行运行如下命令来查看是否还需要安装其它依赖:
flutter doctor
该命令检查你的环境并在命令行窗口中显示报告。Dart SDK已经在打包在Flutter SDK里了,没有必要单独安装Dart。 仔细检查命令行输出以获取可能需要安装的其他软件或进一步需要执行的任务。第一次运行flutter命令(如
flutter doctor
)时,它会下载它自己的依赖项并自行编译。以后再运行就会快得多。缺失的依赖需要安装一下,安装完成后再运行flutter doctor
命令来验证是否安装成功。
(二)在macOS上搭建Flutter开发环境
要安装并运行Flutter,您的开发环境必须满足以下最低要求:
- 操作系统: macOS (64-bit)
- 磁盘空间: 700 MB (不包括Xcode或Android Studio的磁盘空间)
1、去flutter官网下载其最新可用的安装包。https://flutter.dev/docs/development/tools/sdk/releases?tab=macos#macos
2、解压安装包到你想安装的目录,如:
cd ~/development
unzip ~/Downloads/flutter_macos_v0.5.1-beta.zip
//安装的目录
/Users/djmsh/Downloads/flutter
3、将Flutter/bin添加到PATH中请参考下面更新环境变量 :
a. 进入当前用户的home目录:
cd ~/
b. 创建.bash_profile文件:
touch .bash_profile
c. 打开.bash_profile并编辑:
open -e .bash_profile
d. 这样就打开了一个记事本,会显示你之前配置过的path,修改记事本,然后根据自己需要配置。
提示:通过
defaults write com.apple.finder AppleShowAllFiles FALSE ; killall Finder
命令显示隐藏文件//java jdk JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home export JAVA_HOME CLASSPATH=$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar:. export CLASSPATH //android sdk PATH=$JAVA_HOME/bin:$PATH:. export PATH=${PATH}:~/android-sdk-macosx/platform-tools //在这里添加!flutter和dart export PATH=${PATH}:/Users/aiyang/flutter/bin export PATH=${PATH}:/Users/aiyang/flutter/bin/cache/dart-sdk/bin
例如:上面是我配置好的java和android环境变量。
e. command+s保存关闭文件f. 使修改后的配置生效命令:
source .bash_profile
8.验证环境变量是否配置成功:
例如在终端输入以下命令: flutter (此时没有下载Dart-SDK,系统会自行下载)
4、运行 flutter doctor命令检查。
缺失的依赖需要安装一下,安装完成后再运行
flutter doctor
命令来验证是否安装成功。
5、记得在Android的Preferences中找到插件Plugins搜索并安装Flutter插件。
6、如果遇到没有指定AndroidStudio没有指定Dart-sdk的地址,需要手动去配置。(如:/Users/aiyang/flutter/bin/cache/dart-sdk)
7、如果检查不到移动设备。终端命令:(指定android的sdk)
flutter config --android-sdk/Users/aiyang/Android/android-sdk-macosx
(三)使用镜像
由于在国内访问Flutter有时可能会受到限制,下载安装会比较慢,Flutter官方为中国开发者搭建了临时镜像,可以将安装源设置成国内的。大家可以将如下环境变量加入到用户环境变量中,设置方法和上面设置“Flutter添加到PATH”差不多。
JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home
PATH=$JAVA_HOME/bin:$PATH:.
CLASSPATH=$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar:.
export JAVA_HOME
export PATH=${PATH}:~/android-sdk-macosx/platform-tools
export CLASSPATH
export PATH=/Users/djmsh/Downloads/flutter/bin:$PATH
//添加下面这两行:
export PUB_HOSTED_URL=https://pub.flutter-io.cn
export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn
注意: 此镜像为临时镜像,并不能保证一直可用,读者可以参考https://flutter.io/community/china 以获得有关镜像服务器的最新动态。
二、Dart语言介绍
Dart 是谷歌开发的计算机编程语言 ,被用于web、服务器、移动端和物联网等领域的开发。Dart是面向对象的、类定义的、单继承的语言。语法类似C语言和JavaScript,支持接口(interfaces)、混入(mixins)、抽象类(abstract classes)、具体化泛型(reified generics)、可选类型(optional typing) 。
2011年10月10至12日Dart在丹麦奥尔胡斯举行的GOTO大会上亮相。由Lars bak和kasper lund创建。
2015年5月Dart开发者峰会上,亮相了基于Dart语言的移动应用程序开发框架 Sky ,后更名为 Flutter。
Dart vs Java
在VM性能层面,Dart VM在内存回收和吞吐量都进行了反复的优化,因此,Dart在Flutter中可以将GC做到10ms以内。毕竟Google在Go(没用VM但有GC)、JavaScript(v8)、Dalvik(Android上的Java VM)上已经有了很多技术积淀。Dart和Java相比,决胜因素并不会是在性能方面。
在语法层面,Dart要比Java更有表现力。Dart的设计应该是同时借鉴了Java和JavaScript。Dart在静态语法方面和Java非常相似,如类型定义、函数声明、泛型等,而在动态特性方面又和JavaScript很像,如函数式特性、异步支持等。除了融合Java和JavaScript语言之所长之外,Dart也具有一些其它具有表现力的语法,如可选命名参数、
..
(级联运算符)和?.
(条件成员访问运算符)以及??
(判空赋值运算符)。Dart目前真正的不足是生态,但笔者相信,随着Flutter的逐渐火热,会回过头来反推Dart生态加速发展,对于Dart来说,现在需要的是时间。
Dart 和 Flutter
Flutter是谷歌的移动UI框架,可以快速在iOS和Android上构建高质量的原生用户界面。 Flutter可以与现有的代码一起工作。在全世界,Flutter正在被越来越多的开发者和组织使用,并且Flutter是完全免费、开源的。Flutter是一个使用Dart语言开发的跨平台移动UI框架,通过自建绘制引擎,能高性能、高保真地进行移动开发。Dart囊括了多数编程语言的优点,它更符合Flutter构建界面的方式。
一、异步
1、Future
Future
与JavaScript中的Promise
非常相似,一个异步操作的最终完成或失败及其结果值(一个Future只会对应一个结果,要么成功,要么失败)。
(1)Future.then
Future.deleyed()进行延迟2秒后打印data:
Future.delayed(new Duration(seconds: 2),(){
return "hi world!";
}).then((data){
print(data);
});
(2)Future.catchError
如果异步任务发生错误,在catchError
中捕获错误:
Future.delayed(new Duration(seconds: 2),(){
throw AssertionError("Error");
}).then((data){
//成功
print("success");
}).catchError((e){
//失败
print(e);
});
then
方法还有一个可选参数onError
,我们也可以它来捕获异常:
Future.delayed(new Duration(seconds: 2), () {
throw AssertionError("Error");
}).then((data) {
print("success");
}, onError: (e) {
print(e);
});
(3)Future.whenComplete
有时网络请求前需要弹加载框,请求结束使用Future
的whenComplete
回调进行关闭:
Future.delayed(new Duration(seconds: 2),(){
throw AssertionError("Error");
}).then((data){
//成功
print(data);
}).catchError((e){
//失败
print(e);
}).whenComplete((){
//请求结束
});
(4)Future.wait
有些时候需要从多个网络接口获取数据,获取成功后将进行特定的处理后再显示到UI界面上。此时应该使用
Future.wait
,在Future
数组中执行所有Future对象都
成功后,才会触发then
的成功回调,只要有一个Future
执行失败,就会触发catchError错误回调。代码如下:
Future.wait([
Future.delayed(new Duration(seconds: 2), () {
return "hello";
}),
Future.delayed(new Duration(seconds: 4), () {
return " world";
})
]).then((results){
print(results[0]+results[1]);//4秒后显示 hello world
}).catchError((e){
print(e);
});
2、Async/await
Dart中的
async/await
和JavaScript中的async/await
功能和用法是一模一样的。回调地狱(Callback Hell):如果出现大量异步任务依赖其它异步任务的结果时,必然会出现
Future.then
回调中套回调情况。比如,用户先登录,登录成功后会获得用户ID,通过用户ID,请求用户信息,获取到用户个人信息后,保存在本地。
//先分别定义各个异步任务
Future<String> login(String userName, String pwd){
...
//用户登录
};
Future<String> getUserInfo(String id){
...
//获取用户信息
};
Future saveUserInfo(String userInfo){
...
// 保存用户信息
};
login("1","1").then((id){
//登录成功后通过,id获取用户信息
getUserInfo(id).then((userInfo){
//获取用户信息后保存
saveUserInfo(userInfo).then((){
//保存用户信息,接下来执行其它操作
});
});
})
这种在回调里面套回调会导致的代码可读性下降以及出错率提高,并且非常难维护,这个问题被形象的称为回调地狱(Callback Hell)。回调地狱问题在之前JavaScript中非常突出,也是JavaScript被吐槽最多的点,但随着ECMAScript6和ECMAScript7标准发布后,这个问题得到了非常好的解决,而解决回调地狱的两大神器正是ECMAScript6引入了
Promise
,以及ECMAScript7中引入的async/await
。 而在Dart中几乎是完全平移了JavaScript中的这两者:Future
相当于Promise
,而async/await
连名字都没改。
(1)使用Future消除Callback Hell
login("alice","******").then((id){
return getUserInfo(id);
}).then((userInfo){
return saveUserInfo(userInfo);
}).then((e){
}).catchError((e){
print(e);
});
Future
的所有API的返回值仍然是一个Future
对象,所以可以进行链式调用 。
(2)使用async/await消除callback hell
通过
Future
回调中再返回Future
的方式虽然能避免层层嵌套,但是还是有一层回调。使用async/await
能够让我们可以像写同步代码那样来执行异步任务而不使用回调的方式。
task() async {
try{
String id = await login("alice","******");
String userInfo = await getUserInfo(id);
await saveUserInfo(userInfo);
//执行接下来的操作
} catch(e){
//错误处理
print(e);
}
}
async :
表示函数是异步,定义的函数返回一个Future
对象,可以使用then方法添加回调函数。await
:表示等待该异步任务完成;await
必须出现在async
函数内部。
其实,无论是在JavaScript还是Dart中,
async/await
都只是一个语法糖,编译器或解释器最终都会将其转化为一个Promise(Future)的调用链。
3、Stream
Stream
也是用于接收异步事件数据,和Future.wait
不同的是,它可以接收多个异步操作的结果。 也就是说,在执行异步任务时,可以通过多次触发成功或失败事件来传递结果数据或错误异常。Stream
常用于会多次读取数据的异步任务场景,如网络内容下载、文件读写等。举个例子:
Stream.fromFutures([
// 1秒后返回结果
Future.delayed(new Duration(seconds: 1), () {
return "hello 1";
}),
// 抛出一个异常
Future.delayed(new Duration(seconds: 2),(){
throw AssertionError("Error");
}),
// 3秒后返回结果
Future.delayed(new Duration(seconds: 3), () {
return "hello 3";
})
]).listen((data){
print(data);
}, onError: (e){
print(e.message);
},onDone: (){
});
二、变量声明
1、var
它可以接收任何类型的变量,但最大的不同是Dart中var变量一旦赋值,不能再改变其类型,如:
var t;
t = "hi world";
// 下面代码在dart中会报错,因为变量t的类型已经确定为String,
t = 1000;
2、final和const
常量声明用
final
或const 修饰符
。常量只能赋值置一次。两者区别在于:const
变量是一个编译时常量,final
变量在第一次使用时被初始化。被final
或者const
修饰的变量,变量类型可以省略,如:
//可以省略String这个类型声明
final str = "hi world";
//final String str = "hi world";
const str1 = "hi world";
//const String str1 = "hi world";
3、dynamic和Object
Object
是Dart所有对象的根基类,也就是说所有类型都是Object
的子类(包括Function和Null),所以任何类型的数据都可以赋值给Object
声明的对象。dynamic
与var
一样都是关键词,声明的变量可以赋值任意对象。 而dynamic
与Object
相同之处在于,他们声明的变量可以在后期改变赋值类型。
dynamic t;
Object x;
t = "hi world";
x = 'Hello Object';
//下面代码没有问题
t = 1000;
x = 1000;
dynamic
与Object
不同的是,dynamic
声明的对象编译器会提供所有可能的组合, 而Object
声明的对象只能使用Object的属性与方法,,否则编译器会报错。如:
dynamic a;
Object b;
main() {
a = "";
b = "";
printLengths();
}
printLengths() {
// no warning
print(a.length);
// warning:The getter 'length' is not defined for the class 'Object'
print(b.length);
}
三、函数
Dart是一种真正的面向对象的语言,所以即使是函数也是对象,并且有一个类型Function。也就是说函数可以赋值给变量或作为参数传递给其他函数。
1、带返回值函数声明
bool isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
如果不指定返回值类型会默认当做
dynamic类型
处理,注意,函数返回值没有类型推断:
typedef bool CALLBACK();
//不指定返回类型,此时默认为dynamic,不是bool
isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
void test(CALLBACK cb){
print(cb());
}
//报错,isNoble不是bool类型
test(isNoble);
对于只包含一个表达式的函数,可以使用简写语法
bool isNoble (int atomicNumber)=> _nobleGases [ atomicNumber ] != null ;
2、函数作为变量
var say = (str){
print(str);
};
say("hi world");
3、函数作为参数
void execute(var callback) {
callback();
}
execute(() => print("xxx"))
可选的位置参数
包装一组函数参数,用[]标记为可选的位置参数:
String say(String from, String msg, [String device]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
下面是一个不带可选参数调用这个函数的例子:
say('Bob', 'Howdy'); //结果是: Bob says Howdy
下面是用第三个参数调用这个函数的例子:
say('Bob', 'Howdy', 'smoke signal'); //结果是:Bob says Howdy with a smoke signal
可选的命名参数
定义函数时,使用{param1, param2, …},用于指定命名参数。例如:
//设置[bold]和[hidden]标志
void enableFlags({bool bold, bool hidden}) {
// ...
}
调用函数时,可以使用指定命名参数。例如:paramName: value
enableFlags(bold: true, hidden: false);
可选命名参数在Flutter中使用非常多。
结束。谢谢!
参考 https://book.flutterchina.club/chapter1/dart.html