前言
我曾经是Java安卓开发者,进入大学后了解并且转向了Kotlin开发安卓,时至今日现已有了一年时刻,Kotlin带给我的体会实在是太惊艳了,我坚信这便是我最喜爱的言语了。
抱着这种观点,我发现了Flutter+Dart这种笼统的组合,大量的嵌套如同让我在写ifelse,这导致了我迟迟没有触摸Flutter跨渠道结构,当然还有一些其他原因。
其实在之前Flutter的跨渠道能力现已惊艳到我了,这次寒假正好有时机让我学习它。
当我试着用它完结业务时,我发现如同也不是那么不可承受,我甚至还有那么点快感,假如你写过安卓Compose那么你会愈加觉得如此,因为在UI和业务的关系上它真的太简单绑定了,我不再考虑像XML监听数据变化,只可惜Dart语法仍然在一些地方让我感觉到不太好用,仍是得Kotlin来,等等,那我不便是想要Compose吗?
哈哈,不要着急,为什么这个项目是Flutter而不是KMP随后咱们再说。
其实我自身没有很严重的技术癖,面对新的事物和技术,一旦有合适的时机我都是乐意试一试,比起结构的挑选,我愈加享受开发过程,思想转换为代码的那一刻至少我是享受的。
这次挑选Flutter开发不意味着我会一向挑选和追捧它,更不会放弃安卓原生和KMP的学习,因而也期望阅览这篇文章读者意识到这点,我作为原生开发者学习Flutter是期望扩展技术而不是代替原生,Flutter自身也不是这么想的,它更像是给咱们了一个更低的开发门槛,让更多其他领域的创作者完结他们著作的一种前言。
假如你期望快速了解Kotlin开发者运用Dart的开发体会,那么直接跳过下面两部分,直接阅览#错怪的Dart。
动机
我觉得首要动机由两部分组成吧,一部分是跨渠道开发自身是我感兴趣的方向之一,另一边是未来作业或许需求吧,现在来看国内跨渠道趋势仍是比较明显的。
不过我更期望这次项目是体会移动跨渠道开发,而不是真实的深入学习移动跨渠道开发。为此,我期望能够找到学习成本和项目质量相平衡的开发方式,很惋惜我没有那么多的精力做到既要还要,这是我有必要面对的挑选。
面对众多跨渠道结构下我仍是挑选了Flutter,这首要与它的跨桌面端和生态完善有关,毫无疑问,Flutter有许多的成品组件,这让我能够快速轻松的上手跨渠道开发。
为什么是Flutter
这个项目的首要功用便是播映器,只不过这个播映器比较特殊,后续文章咱们会揭晓它。
单就网络音频播映器开发使命而言,假设运用KMP或许没有现成封装好的库来给我用,或许许多开发者考虑没有就造一个,很惋惜,我不太具备这样的能力,咱们需求一起对接多个渠道的媒体播映,无论开发周期,单就这样的使命对我现已是很难了。
好吧,我想有必要供认我很菜,可是事实如此,因而我挑选了愈加成熟的Flutter,防止我写不出来,哈哈哈哈。
不过咱们今日先不谈Flutter,咱们看看Dart。
错怪的Dart
对Dart的刻板印象是从我第一次见到Flutter的语法时形成的,第一次见到Dart时我还没有触摸Kotlin。
看着有点像Java,还有很多_的姓名是什么鬼东西、怎样要写这么多return、为什么有个?、总归便是反人类啊!!!
当我真实测验去编写Flutter程序时,我发现,嗯,错怪Dart了,特别是因为我了解Kotlin后,Kotlin和Dart也有几分相似之处,这体现在一些语法特性上。
空安全
可空类型在Kotlin上能够说相当不错,在Dart上也能够体会到它,虽然它是类型前置,可是写法却是相同的在类型后加上”?”即可。
class AudioMediaItem {
String title;
String description;
AudioMediaType type;
String? mediaUrl;
String? bvId;
//省略其他代码.....
}
当咱们企图运用AudioMediaItem的目标时,咱们就能够像Kotlin那样做,留意mediaUrl现在是可空的。
audioMediaItem?.mediaUrl
,假如咱们以为这个属性一定有值,那么就能够运用audioMediaItem!.mediaUrl
,需求留意的是,dart中是”!”而不是”!!”。
假如你期望运用Kotlin的Elvis操作符 ?: ,那么你能够这么做
audioMediaItem?.mediaUrl ?? "default";
对应Kotlin的
audioMediaItem?.mediaUrl ?: "default"
在这方面,dart和Kotlin是非常相似的,因而,你能够非常平滑的搬迁这部分的开发体会和理解。
推迟初始化
在Kotlin中,咱们能够运用lateinit var
定义一个非空推迟初始化的变量,通俗的讲便是定义一个非空类型,可是不给初始值。dart也有对应从要害字,那便是late
了。
late String name;
相当于Kotlin的
lateinit var String name
咱们知道推迟初始化意味着这个值必定有值,仅仅咱们期望这个值在代码运行过程中产生并且初始化,初始化后再运用该值,不然就会空指针了。
假如你现已熟悉了Kotlin的lateinit,那这儿也能够平滑搬迁了。
可是在Android Studio 2023.1.1我发现个有意思的事情。
late String? name;
ide没有提示这是过错的,我没试着运行,可是我觉得这应该是不合理的。
扩展函数
扩展函数在Kotlin傍边能够说相当重要,许多内置函数都是这个特性所带来的。
在Kotlin中,咱们通过 被扩展的类名.扩展函数名(){} 这样的写法就完成了一个扩展函数。
fun String.toColorInt(): Int = Color.parseColor(this)
Dart中也存在扩展函数的语法糖!
extension StringExtension on String {
/// 将字符串的首字母大写
String capitalize() {
if (isEmpty) {
return this;
}
return '${this[0].toUpperCase()}${substring(1)}';
}
}
其间,StringExtension仅仅这个扩展的姓名,相当于一个标志,能够随意起,on String则代表扩展String类,那么capitalize 自然便是扩展的办法名了。
将Kotlin的内置函数带入
Kotlin的内置函数实在是太棒了,下面以also和let为比如,模仿了Kotlin的扩展函数,只可惜Dart的lambda不太能像Kotlin那样,仍是有一些分裂。
extension AlsoExtension<T> on T {
T also(void Function(T) block) {
block(this);
return this;
}
}
extension LetExtension<T> on T {
R let<R>(R Function(T) block) {
return block(this);
}
}
//用法
String demo = "xada".let((it) => "${it}xadadawdwad");
emm不过因为没办法直接传this,在变量很长或者类型可空时还有点用。
顶层函数
Kotlin中,咱们有时候需求在大局运用一些函数,可是不期望写在类里,而是随时随地直接能够调用或者拿到。
留意这些代码不在类里
val json = Json {
prettyPrint = true
isLenient = true
ignoreUnknownKeys = true
}
var retrofit = Retrofit.Builder()
.baseUrl("https://api.juejin.cn/")
.addConverterFactory(json.asConverterFactory(MediaType.parse("application/json;charset=utf-8")!!))
.build()
在某个类需求咱们就直接写retrofit.xxxx() 就能够了,咱们不需求再独自从类中找。
Dart也有这样的功用
final _cookieJar = CookieJar();
final Dio dioClient = Dio(BaseOptions(
baseUrl: baseUrl,
connectTimeout: const Duration(seconds: 5),
receiveTimeout: const Duration(seconds: 5),
contentType: Headers.jsonContentType,
persistentConnection: true,
))
..transformer = BackgroundTransformer()
..let((it) {
if (!kIsWeb) {
it.interceptors.add(CookieManager(_cookieJar));
return it;
} else {
return it;
}
});
上面的比如仅仅写了变量,写函数也是相同的,都能够直接在大局任何的方位调用。
高阶函数
在Kotlin中,高阶函数是特殊的一种函数,这种函数承受了另一个函数作为参数。
咱们以Kotlin的forEach函数为比如:
public inline fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit {
for (element in this) action(element)
}
// 用法
fun main() {
val demoList = listOf("da", "da", "da")
demoList.forEach {
println(it)
}
}
forEach自身扩展了Iterable,可是它的参数非常特殊,咱们看看action参数的类型:
(T) -> Unit,这是Kotlin匿名函数的写法,意味着这个函数有一个参数,类型为T泛型,这个参数也没有起姓名,所以就只要类型T在。
这种状况,在Java中这种完成一般是接口类,咱们需求实例化这个匿名类,假设这个接口只要一个办法,那么就能够转换为lambda的写法。
在Kotlin里咱们能够直接写为lambda的方式,要方便很多,因为只要一个参数,那么kotlin默许就叫it了。
OK回顾完Kotlin,咱们看看Dart:
void forEach(void action(E element)) {
for (E element in this) action(element);
}
//用法
List<String> demoList = ["da","da","da"];
demoList.forEach((element) {
print(element);
});
其实不同不大,仅仅咱们需求写void当作这个参数的类型,内部写法没有太大差异。
不过,Dart的lambda愈加贴近JS,写法根本上是一模相同。
信任假如你现已把握了Kotlin的高阶函数,那么在Dart测验也是不错的。
运算符重载
Kotlin傍边有个不太常用的东西,叫运算符重载,它在Dart中也有。
public operator fun <T> Collection<T>.plus(elements: Iterable<T>): List<T> {
if (elements is Collection) {
val result = ArrayList<T>(this.size + elements.size)
result.addAll(this)
result.addAll(elements)
return result
} else {
val result = ArrayList<T>(this)
result.addAll(elements)
return result
}
}
//用法
val demoList = listOf("da", "da", "da") + listOf<String>("add")
能够看到kotlin通过operator要害字合作扩展函数完成了这个功用,dart也能够模仿这种手法:
// 模仿
extension ListPlusOperatorExtension<T> on List<T> {
List<T> operator +(List<T> elements) {
List<T> result = this;
addAll(elements);
return result;
}
}
// 用法
List<String> demo1 = ["da","da"];
List<String> demo2 = ["da","d1a"] + demo1;
不过这儿的加减乘除便是operator + 了。
总结
能够看得出,Dart也有部分咱们在Kotlin中喜爱的特性,假如你现已把握了Kotlin的根本语法,那么信任Dart对你来说也不是太大问题,你能够平滑的搬迁一些在Kotlin中的知识到Dart上去。
起初我是很坑距运用Flutter的,现在看见Dart的特性,我好像又承受了一些,好吧,对于Flutter开发、布局约束和其他感受我在下一篇文章再共享给咱们吧。
最终感谢咱们看到这儿,还有什么好玩的特性欢迎在下面留言,文章内容有过错请指出。