Flutter笔记
Flutter环境搭建
获取 Dart SDK | Dart
dart-pub | 镜像站使用帮助 | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror
Flutter、Dart SDK镜像资源 - 掘金 (juejin.cn)
Index of /flutter/dart-archive/channels/stable/release/3.2.6/sdk/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror
Flutter环境配置(window10环境) - 简书 (jianshu.com)
搞搞flutter,首先是环境配置,此前提是已经安装Android studio和对应的Android SDK。废话不多说,看具体步骤:
一,从如下地址下载对应的flutter SDK,点击如图下载最新版本sdk:
flutterSDK下载地址:https://flutter.dev/docs/get-started/install/windows
二,将sdk复制到系统盘并解压,位置随意。如下图所示
三,打开解压的flutter文件夹,找到bin,复制如下图地址
四,桌面找到 此电脑–>右击选择属性–>高级系统设置–>环境变量–>找到系统变量–>Path–>编辑–>新建–>粘贴第三步复制的地址–>点击确定保存
五,配置国内镜像。桌面找到 此电脑–>右击选择属性–>高级系统设置–>环境变量–>找到用户变量–>点击新建
FLUTTER_STORAGE_BASE_URL="https://mirrors.tuna.tsinghua.edu.cn/flutter"
PUB_HOSTED_URL="https://mirrors.tuna.tsinghua.edu.cn/dart-pub"
六,重启电脑
七,在桌面左下角输入cmd,打开命令提示符。输入 flutter doctor。检查配置项。如下图所示:
八,发现没有配置Android sdk,补充配置一下,找到用户变量,点击新建,如下图所示。
ANDROID_HOME=D:\AndroidSDK //该sdk地址是你安装Android studio的时候配置的sdk的地址
下图是Android studio中Android SDK的位置:
九,重新输入cmd,打开命令提示符,输入 flutter doctor,如下图所示:
十,出现感叹号! Some Android licenses not accepted. To resolve this, run: flutter doctor --android-licenses按照他说的 输入 flutter doctor --android-licenses,一路y下去即可。如下图所示:
重新输入 flutter doctor检查一下,如下图所示:表示只有Android studio的两个插件没有安装了。
十一,打开Android studio,安装dart和flutter两个插件重新运行flutter doctor 如下图:
都是绿色的小勾勾,表示安装成功。
十一,Android toolchain问题
网上许多教程可能flutter doctor 后直接就是下面的情况:
此时直接按提示运行flutter doctor --android-licenses 一路按y即可
但现在可没这么简单了,之前也提到过 在安装Android Studio过程中安装的Android sdk时不完整的,所以大多会是
根据您的错误提示,您需要进行以下两个步骤来解决Android工具链的问题:
-
安装 cmdline-tools 组件:
打开命令行,导航到你的Android SDK的cmdline-tools
目录。如果尚未下载或安装,可以按照提示在SDK的tools目录下运行以下命令(请将path/to/sdkmanager
替换为实际的sdkmanager路径):path/to/sdkmanager --install "cmdline-tools;latest"
这将会安装最新的cmdline-tools组件。
-
接受 Android SDK 许可协议:
在命令行中运行以下Flutter命令以接受所有未接受的Android SDK许可:flutter doctor --android-licenses
然后,当命令行列出所有许可时,按’y’键接受每个许可。
执行完上述步骤后,再次运行 flutter doctor
检查环境是否配置正确。如果一切顺利,关于Android工具链和许可证的状态问题应该会得到解决。
Android Studio设置国内镜像代理教程(HTTP Proxy)
Android Studio是在谷歌的服务器上,初次安装Android Studio时下载SDK等必定失败,由于国际环境原因,大陆是无法正常访问谷歌的,所以我们在使用Android Studio时需要设置HTTP Proxy 也就是网络代理,下面就来看看操作教程吧。
Android Studio设置HTTP Proxy
1.首次打开会自动弹出HTTP Proxy的设置项,如果没有请进入主界面后点击:File→Settings…→System Settings → HTTP Proxy(或者按快捷键:Ctrl+Alt+S,然后依次找到System Settings → HTTP Proxy)
2.打开后按下图,也就是选中“Auto-detect proxy settings”,勾选下方“Automatic proxy configuration URL”,填入国内的某个镜像站。
3.这里,我选择的是如下镜像站
mirrors.aliyun.com:80
4.配置完成后,就可以使用了,其他镜像站请参考下方的“Android SDK在线更新镜像服务器”。
1.阿里云镜像站地址:
mirrors.aliyun.com 端口:80
2.清华大学镜像站地址:
mirrors.tuna.tsinghua.edu.cn 端口:80
3.北京外国语大学镜像站地址:
mirror.bfsu.edu.cn 端口:80
4.中国科学院开源协会镜像站地址:
IPV4/IPV6: mirrors.opencas.cn 端口:80IPV4/IPV6: mirrors.opencas.org 端口:80IPV4/IPV6: mirrors.opencas.ac.cn 端口:80
5.上海GDG镜像服务器地址:
sdk.gdgshanghai.com 端口:8000
6.北京化工大学镜像服务器地址:
IPv4: ubuntu.buct.edu.cn/ 端口:80IPv4: ubuntu.buct.cn/ 端口:80IPv6: ubuntu.buct6.edu.cn/ 端口:80
7.大连东软信息学院镜像服务器地址:
mirrors.neusoft.edu.cn 端口:80
8.腾讯Bugly 镜像:
android-mirror.bugly.qq.com 端口:8080
来源:https://www.jianshu.com/p/fc97fccdf578
Android Studio 国内镜像代理设置(如果设置之后还是远程仓库下载失败,请仔细阅读其内容就可以解决了)-CSDN博客
Android Studio 配置flutter开发环境教程(超详细)_flutter config–android sdk-CSDN博客
使用Android Studio创建项目
-
安装flutter插件
点击pugins直接搜索flutter然后install即可,它会提示此插件依赖dart,直接确定就好
装好后确定就会回到创建项目页面
点击第二项创建flutter project点击next后就是项目配置:
dart语言
as关键字
在Dart语言中,as
关键字有多种用法:
-
类型转换:
-
当你想要将一个对象显式地转换为另一种类型时,可以使用
as
关键字。如果转换是安全的(即目标类型与源类型兼容或者源对象实际上是目标类型的实例),则转换会成功;否则,如果转换失败,则在运行时会抛出TypeError
异常。dynamic value = "Hello"; String strValue = value as String; // 安全转换,因为value实际是一个String。 int intValue = value as int; // 不安全转换,如果执行此行代码会抛出TypeError,因为字符串不能直接转换为整数。
-
-
库前缀导入:
-
在Dart中,当两个或多个库中有同名的顶级标识符冲突时,可以使用
as
来给导入的库指定别名,以此来避免名称冲突。import 'package:lib1/my_library.dart' as lib1; import 'package:lib2/my_library.dart' as lib2; void main() { lib1.MyClass classFromLib1 = lib1.MyClass(); lib2.MyClass classFromLib2 = lib2.MyClass(); }
-
-
异步流(Stream)中的类型过滤:
-
在处理异步数据流时,可以使用
.cast()
方法配合as
进行类型转换,确保流中的事件符合特定类型。Stream<Object> objectStream = ...; Stream<String> stringStream = objectStream.cast<String>();
-
-
泛型类和方法中:
- 类型参数上下文中不直接使用
as
关键字,但在类型推断和类型约束中,它可能隐含地用于指示类型转换。
- 类型参数上下文中不直接使用
注意:对于异步编程,Dart 使用 async
和 await
关键字而不是 as
,这些关键字与异步函数定义以及等待异步操作完成相关联。
dynamic关键字
在Dart语言中,dynamic
是一种类型注解,它表示变量可以持有任何类型的值。当你声明一个变量为 dynamic
类型时,编译器不会对该变量进行类型检查,这给予了你更大的灵活性,但也意味着可能在运行时出现类型错误。
例如,在Dart中:
dynamic value;
value = 42; // 正确,因为整数是合法的Dart对象
value = "Hello"; // 正确,字符串也是合法的Dart对象
value.callSomeMethod(); // 运行时如果value不是一个具有callSomeMethod方法的对象,则会抛出异常
// 在Dartz库的上下文中,
// dynamic 可能用于表示函数式编程中的某种泛型或不特定类型的数据结构,
// 但在Dartz库本身并不直接定义或使用特殊的 dynamic 类型概念。
在与Dartz库相关的函数式编程场景下,虽然Dartz通常鼓励静态类型以确保类型安全,但如果你将Dart的 dynamic
类型用于Dartz库的数据结构如 Maybe<dynamic>
或 Either<dynamic, String>
等,那么这些数据结构将会允许存储任意类型的值,但这会牺牲掉静态类型带来的诸多优势,包括编译时错误检测和IDE智能提示等。
判空运算符—?、??、??=
在Dart语言中,用于空值处理的运算符包括:
-
条件成员访问运算符
?.
:-
当尝试访问可能为
null
的对象的属性或方法时使用。var person = maybeNullPerson; // 可能是 null var name = person?.name; // 如果 person 为 null,则 name 也为 null,否则访问 person.name
这个运算符会安全地返回
null
而不是抛出异常。如果链式调用中的任何一个点为null
,则整个表达式将短路并返回null
。
-
-
空合并运算符
??
:-
当需要提供一个默认值以防止
null
值时使用。String nullableString; String nonNullableString = nullableString ?? "default value";
如果
nullableString
为非null
,那么nonNullableString
将等于nullableString
的值;如果nullableString
为null
,则nonNullableString
将被赋予 “default value”。
-
-
空合并赋值运算符
??=
:-
只有当变量为
null
时才进行赋值操作。String? possiblyNullVar; possiblyNullVar ??= "initialized on demand";
在这个例子中,只有当
possiblyNullVar
为null
时,才会执行possiblyNullVar = "initialized on demand"
。如果possiblyNullVar
已经有一个非null
的值,此运算符什么都不会做,保持原值不变。
-
这些运算符都是 Dart 空安全特性的一部分,旨在帮助开发者编写更安全、简洁的代码,避免因意外的 null
引发运行时错误。
switch…case
在Dart语言中,switch...case
语句用于基于表达式的值执行不同的代码块。以下是 switch...case
的基本用法:
// 声明一个变量或表达式
var someValue = ...; // 可以是整数、字符、枚举或其他允许的类型
switch (someValue) {
case value1:
// 当 someValue 等于 value1 时执行这里的代码
statements1;
break; // 如果需要在执行完statements1后立即跳出switch结构,则使用break
case value2:
// 当 someValue 等于 value2 时执行这里的代码
statements2;
break;
// 可以有任意数量的case子句
...
default:
// 当 someValue 不等于任何一个case标签的值时执行这里的代码
defaultStatements;
break; // 在default分支中使用break也是可选的,因为默认情况下会在这里停止执行switch结构
}
// switch 结构结束后的其他代码
...
注意事项:
switch
表达式的结果必须是整数、字符串(从 Dart 2.3 版本开始支持)、或者实现了==
运算符和hashCode
方法的对象。- 每个
case
子句后面跟着一个要匹配的常量表达式。 - 执行流程会进入第一个与
switch
表达式结果相等的case
分支,并执行该分支中的代码。 - 使用
break
关键字来终止当前case
分支的执行并跳出整个switch
结构。如果没有break
,控制流将“贯穿”到下一个case
子句,直到遇到break
或到达switch
结束为止。 default
子句是可选的,用于提供一个当所有case
都不匹配时的默认行为。
Class
您提供的Dart代码片段定义了一个名为 Cat
的类,但是缺少了构造函数来初始化实例的属性。在Dart中,如果你不提供任何构造函数,编译器会自动生成一个无参数的默认构造函数。然而,一旦类中有可nullable的非final字段(如您的 name
和 age
),默认构造函数不会给它们赋予初始值,所以在创建 Cat
实例时这些字段将是未初始化的。
为了让这个类能正确实例化并赋初值,您可以添加一个构造函数:
class Cat {
String name;
int age;
// 添加构造函数以初始化成员变量
Cat(this.name, this.age);
}
现在当你创建 Cat
类的实例时,需要传递 name
和 age
的初始值:
var myCat = Cat('Mittens', 3); // 创建一个名字为'Mittens'、年龄为3岁的猫实例
当然,如果您希望 name
或 age
在没有传入值时有默认值,可以这样定义构造函数:
class Cat {
String name;
int age;
// 添加构造函数,并设置默认值
Cat({this.name = '未知', this.age = 0});
}
这样即使不传递参数也能创建 Cat
实例,并且其 name
和 age
将分别默认为 '未知'
和 0
。
类的构造方法
您提供的代码中包含了两种不同的构造方法(构造函数):
- 带有初始化逻辑的构造函数:
Cat(String name, int age) {
this.name = name; // 使用 'this' 关键字来明确指定当前实例的属性
this.age = age;
}
在这个构造函数中,通过传入的 name
和 age
参数直接初始化了实例的同名属性。这种方式下,即使成员变量使用了 late
关键字,也会在构造函数执行时立即赋值。
- 初始化列表构造函数:
Cat(this.name, this.age);
这个构造函数是简化的构造器语法,它使用了初始化列表。当参数名与类中的属性名相同时,可以直接用 this.
的形式来引用它们,并且会自动完成对相应属性的初始化。在这种情况下,由于我们已经提供了初始值,所以对于 late
类型的属性来说也是安全的,它们会在构造过程中被初始化。
结论:这两种构造函数都可以用来正确地初始化带有 late
关键字的 name
和 age
属性。在实际开发中,如果不需要额外的初始化逻辑,通常更倾向于使用第二种简洁的初始化列表构造函数。
import用法
在Dart中,import
关键字用于导入其他库或源文件中的类、函数或其他定义。以下是 import
的基本用法:
-
基本导入:
import 'package:example_package/example_file.dart';
这种形式用于导入 pub(Dart的包管理器)依赖或者项目内的库。这里的
'package:example_package/example_file.dart'
表示要导入的文件路径。 -
导入并指定别名:
import 'package:example_package/example_file.dart' as myAlias;
当需要给导入的库或文件指定一个别名以避免命名冲突时使用此语法。例如,在上面的例子中,你可以通过
myAlias
来引用导入文件中的所有内容。 -
仅导入部分内容:
import 'package:example_package/example_file.dart' show MyClass, MyFunction;
使用
show
关键字可以指定只导入指定的类或函数等符号。在上述例子中,只会导入MyClass
类和MyFunction
函数。
或者import 'package:example_package/example_file.dart' hide MyClass;
使用
hide
关键字可以排除指定的类或函数等符号。这意味着除了MyClass
之外,example_file.dart
中的所有其他内容都会被导入。 -
deferred import(延迟加载导入):
import 'package:example_package/example_file.dart' deferred as myDeferredImport;
延迟加载导入会在运行时而不是编译时加载库,通常用于大型库以提高应用启动速度。在使用这些库之前,需要通过
.loadLibrary()
方法来加载它们。 -
混合使用 show 和 hide:
import 'package:example_package/example_file.dart' show MyClass, AnotherClass, hide MyFunction;
同时使用
show
和hide
可以更精细地控制导入的内容。
注意:对于 Dart SDK 内置的库,可以直接导入,如:
import 'dart:math'; // 导入Dart内置的数学库
枚举类
在Dart语言中,枚举(Enum)是一种特殊的类,用于定义一组命名的、预定义的常量值。枚举可以为这些常量提供有意义的名称,并且每个枚举值都有一个索引和唯一标识。
创建枚举的基本语法如下:
enum Color {
red,
green,
blue
}
在这个例子中,Color
是枚举类型的名字,而 red
、green
和 blue
是该枚举类型的三个实例或成员。
每个枚举值都有一个默认索引,从0开始自动递增。例如,red
的索引是 0,green
的索引是 1,blue
的索引是 2。可以通过 .index
属性获取枚举值的索引:
int redIndex = Color.red.index; // redIndex 将会是 0
此外,你可以访问枚举的当前值:
Color myColor = Color.green;
print(myColor); // 输出: Color.green
如果需要自定义枚举值对应的字符串或者其他数据,可以给枚举成员指定一个值:
enum Color {
red('红色'),
green('绿色'),
blue('蓝色');
final String description;
Color(this.description);
String get value => description;
}
void main() {
print(Color.red.value); // 输出: 红色
}
在这个例子中,我们为每个颜色枚举添加了一个描述字段,并提供了获取描述的方法 value
。
【dart相关问题】
有问题。
/// 可选位置参数---用[]包裹
void insertUser1(int id, String name, [int age]) {
String intro = "id:$id,name:$name";
if age:
intro = intro+"age:$age";
print(intro);
}
这段代码中存在几个问题:
-
可选位置参数的定义是正确的,但调用时需要在括号内指定或者省略。
[int age]
表示age
是一个可选的位置参数,默认值为null
。 -
在条件判断中使用了变量
age
而不是if (age != null)
或if (age != null && age != '')
(如果考虑空字符串的情况)来检查age
是否有值。
修正后的代码应该是这样:
void insertUser1(int id, String name, [int age]) {
String intro = "id:$id,name:$name";
if (age != null) { // 检查 age 是否有非 null 值
intro += ",age:$age"; // 使用 += 连接字符串而非 +
}
print(intro);
}
现在,当你调用 insertUser1(1, 'John')
时,不会包含年龄信息;而调用 insertUser1(1, 'John', 30)
时,则会打印出带有年龄信息的结果。
【error】 06-function.dart:30:44: Error: The parameter 'age' can't have a value of 'null' because of its type 'int', but the implicit default value is 'null'. Try adding either an explicit non-'null' default value or the 'required' modifier. void insertUser1(int id, String name, [int age]) { ^^^
我明白了,Dart 2.12 版本引入了空安全特性,并在 Dart 2.13 版本默认开启。这意味着 int
类型的参数不能为 null
,但你提供的可选参数 age
没有指定非 null
的默认值。
要解决这个问题,请根据你的需求选择以下任一方式:
- 如果
age
参数可以是null
并且希望保持其为可选参数,则将其类型更改为int?
:
void insertUser1(int id, String name, [int? age]) {
String intro = "id:$id,name:$name";
if (age != null) {
intro = "$intro,age:$age";
}
print(intro);
}
- 如果
age
参数必须提供一个非null
值,则移除方括号并添加required
关键字:
void insertUser1(int id, String name, required int age) {
String intro = "id:$id,name:$name,age:$age";
print(intro);
}
现在,无论是哪种情况,代码都不会报错,并且符合 Dart 的空安全规范。