关于kotlin:一文带你吃透Kotlin类与对象

公众号「罕见猿诉」        原文链接 一文带你吃透Kotlin类与对象Kotlin是多范式通用编程语言,对面向对象编程(OOP)天然也提供了全方位的反对。通过先前一篇文章,学习了应用Kotlin进行根本面向对象编程的办法,本文将在前文根底之上持续深刻的学习面向对象编程的高级个性,以可能写出更加合乎OO的代码,并可能从容应对一些简单的OOP场景。 留神结构的程序在结构对象过程中,有三个中央能够对成员进行初始化:1)是在首构造方法(Primary constructor);2)是在申明成员的同时进行初始化,或者是在初始化代码块(init {...})中;3)是在主要构造方法(Secondary constructor)中。 要留神它们之间的区别和执行程序,首构造方法是最先执行的,但它不能运行代码,只能进行赋值;成员申明和初始化代码块(init {...})是首构造方法的一部分,因而要先于主要构造方法。主要构造方法是最初执行,并且主要构造方法肯定要委托到首构造方法。成员申明和初始化代码块之间则依赖于书写的程序,从上到下执行。 尽管编译器有它的规定来保障程序,但为了可读性和可维护性,咱们不应该齐全依赖编译器。这里倡议的形式是: 把类的最外围的成员放在首构造方法,如必须要依赖的参数,公开的成员,类型体系中的核心成员等,这些应该间接放在首构造方法中,并按重要的程序进行申明,这样也能不便进行依赖注入和测试Mock对象替换。公有成员应该在类中申明,并且在申明时进行初始化,如果无奈初始化就标记为提早初始(late init)。初始化代码块,应该做一些简单的初始化过程,或者成员之间有关联的初始化,或者做一些结构实现之后的操作。比方像在ViewModel中,结构之后,可能执行拉取数据,这就非常适合放在init {...}之中。不倡议应用主要构造方法,能够用给首构造方法的参数设置默认值的形式来进行成员参数上的重载。初始化代码块要放在所有成员申明之后,以保障执行程序。扩大浏览Classes和Properties。 妙用late init通常成员的初始化能够在申明时实现,比方像汇合或者一些简略的原始类型对象(Int, Float, String等)。但如果初始化过程比较复杂,或者初始值较难取得,这种状况下,就适宜标记为提早初始化late init,而后在适合的机会对成员进行初始化(比方零碎框架层的回调中,或者依赖注入等等)。应用一个未初始化的late init成员时会抛出一个叫做UninitializedPropertyAccessException的异样,能够在应用成员变量前用.isInitialized来判断成员变量是否初始化过: if (foo::bar.isInitialized) { println(foo.bar)}能够发现,对于Android 开发来说late init相对十分有用,因为对于零碎组件,咱们无奈在其构造方法中进行成员初始化,通常都是在第一个回调(如onCreate)中进行初始化,而这些变量全都应该用late init来标记。 另外,须要留神的是,成员是否有被初始化与成员是否是非法值(如null)并不是同一回事,初始化是第一次对成员对象赋值,赋的什么值(失常对象or null)虚拟机并不关怀,但只有有过赋值后变量就初始化过了。因而,用late init能够帮忙缩小null查看。 还须要留神的是,提早初始化late init与属性委托也不是同一回事,late init通常用于外部公有的成员变量,而属性委托通常用于对外开放的公开成员。 扩大浏览Properties。 函数式接口 接口(interfaces)是更高级别的形象,专一于行为的形象,用以实现对象间契约式行为交互。这一部分不打算具体解说interface的应用,而是重点关注函数式接口(function interface)。Kotlin中的接口与Java 8中的接口是一样的,不再全是形象办法了,能够有默认办法,也就是对接口的办法增加默认的实现,没有默认实现的办法就是形象办法了(Abstract method)。只有一个形象办法的接口称之为函数式接口(functional interface),或者单个形象办法接口(Single Abstract Method interface)。用fun interface来申明,如: fun interface IntPredict { fun accept(i: Int): Boolean}函数式接口的最大劣势在于,实现接口时能够简化到只用一个lambda,如: val isEnv = IntPredict { it % 2 == 0 }留神,只有用fun interface申明的含有一个形象办法的接口才是函数式接口,能力用lambda。对于一般接口,如果它仅含有一个形象办法,能够转化为函数式接口,比方原接口是酱紫的: interface Printer { fun print()}那么,能够间接定义一个fun interface Printer就能够了: ...

February 27, 2024 · 1 min · jiezi

关于kotlin:专家之路上的Flow高级秘籍

公众号「罕见猿诉」        原文链接 专家之路上的Flow高级秘籍 『君不见,黄河之水天上来,奔流到海不复回。』 学习与河流一样,一方面学无止境,又是逆水行舟,逆水行舟,因为其他人都在卷。前文一篇文章讲了Flow的根底,大多数状况下够用了,然而不能进行卷,因为你不卷,就会被他人卷。一旦波及到简单的利用场景,就须要用到一些高级的API。明天就来学习一下Flow的高级个性,当遇到问题时也能更从容的应答。 上下文切换Flow是基于协程的,是用协程来实现并发,后面也提到过像[flow {...}](),在上游生产数据,以及中游做变幻时,都是能够间接调用suspend,耗时甚至是阻塞的函数的。而终端操作符如[collect]()则是suspend的,调用者(也就是消费者)须要负责确保collect是在协程中调用。咱们还晓得Flow是是冷流,消费者终端才会触发上游生产者生产,所以对于flow {...}来说,它的上游和中游运行的上下文来自于终端调用者的上下文,这个叫做『上下文保留』(context preservation),咱们能够用一个 来验证一下: fun main() = runBlocking { // Should be main by default simple().collect { log("Got: $it") } // Collect in a specified context withContext(Dispatchers.Default) { simple().collect { log("Now got: $it") } }}private fun simple(): Flow<Int> = flow { log("Started the simple flow") for (i in 1..3) { delay(100) log("Producing $i") emit(i) }}输入如下: [main @coroutine#1] Started the simple flow[main @coroutine#1] Producing 1[main @coroutine#1] Got: 1[main @coroutine#1] Producing 2[main @coroutine#1] Got: 2[main @coroutine#1] Producing 3[main @coroutine#1] Got: 3[DefaultDispatcher-worker-1 @coroutine#1] Started the simple flow[DefaultDispatcher-worker-1 @coroutine#1] Producing 1[DefaultDispatcher-worker-1 @coroutine#1] Now got: 1[DefaultDispatcher-worker-1 @coroutine#1] Producing 2[DefaultDispatcher-worker-1 @coroutine#1] Now got: 2[DefaultDispatcher-worker-1 @coroutine#1] Producing 3[DefaultDispatcher-worker-1 @coroutine#1] Now got: 3从这个 能够分明的看到,Flow的context是来自于终端调用者的。 ...

February 20, 2024 · 3 min · jiezi

关于kotlin:DataBinding系列之基础使用

1.前言DataBinding, 又名数据绑定,是Android开发中十分重要的根底技术,它能够将UI组件和数据模型连接起来,使得在数据模型发生变化时,UI组件自动更新,从而节俭了大量的代码和工夫。DataBinding的原理是通过编写XML布局文件,在其中应用特定的标签和语法,将UI组件和数据模型连接起来。当布局文件被加载时,DataBinding会主动生成绑定代码,从而将UI组件和数据模型关联起来。 通过学习DataBinding基础知识,能够让你的代码速度翻倍,进步开发效率和代码品质。因而,如果你心愿在Android开发中取得更高的成功率和更快的倒退速度,那么请务必学习DataBinding技术,把握其基础知识,让本人成为一名高效率的Android开发者! 那么话不多说,让咱们间接直奔主题。接下来我将从实用性的角度,来逐个解说DataBinding的根底应用,文章开端会给出示例代码的链接地址,心愿能给你带来启发。 2.筹备工作2.1 启用1.DataBinding启用 android { dataBinding { enabled = true }}2.ViewBinding启用 android { buildFeatures { viewBinding true } }2.2 快捷方式在你的布局中找到最外层的布局,将光标放在如图地位。 Windows 请按快捷键 Alt + 回车Mac 请按快捷键 option + 回车 3.DataBinding绑定3.1 数据类型通常咱们在DataBinding中绑定的数据类型是ViewModel或者是AndroidViewModel,它俩都是生命周期可感知的,惟一的区别是AndroidViewModel能够获取到利用的上下文Application。 3.2 数据创立ViewModel的创立通常是通过ViewModelProvider进行创立和获取。 ViewModelProvider(this).get(Xxx::class.java)而在ViewModel中,通常应用MutableLiveData作为可变UI响应数据类型。相比拟LiveData而言,它凋谢了批改值的接口,上面是一个ViewModel的简略例子: class RecyclerViewRefreshState(application: Application) : AndroidViewModel(application) { val title = MutableLiveData("RecyclerView的刷新和加载更多演示") val isLoading = MutableLiveData(false) val sampleData = MutableLiveData<List<SimpleItem>>(arrayListOf()) val loadState = MutableLiveData(LoadState.DEFAULT) val layoutStatus = MutableLiveData(Status.DEFAULT)}当然了,如果你有一个LiveData会随着一个或多个LiveData的变动而变动,这个时候你可能就须要应用MediatorLiveData,即合并LiveData。 这里我简略利用MediatorLiveData实现一个组合的LiveData--CombinedLiveData。 open class CombinedLiveData<T>(vararg liveData: LiveData<*>, block: () -> T) : MediatorLiveData<T>() { init { value = block() liveData.forEach { addSource(it) { val newValue = block() if (value != newValue) { value = newValue } } } }}fun <R, T1, T2> combineLiveData( liveData1: LiveData<T1>, liveData2: LiveData<T2>, block: (T1?, T2?) -> R) = CombinedLiveData(liveData1, liveData2) { block(liveData1.value, liveData2.value) }这个时候,咱们就能够通过combineLiveData办法将两个LiveData组合起来,造成一个新的LiveData。上面我简略给出一个示例代码: ...

June 29, 2023 · 3 min · jiezi

关于kotlin:从-Java-到-Kotlin-介绍-Kotlin

B站视频:https://www.bilibili.com/vide...语法层面可空对象(和 C# 的 <Nullable>enabled</Nullable> 类似) Int 和 Int? 是两种不同的类型;String和 String? 也是两种不同的类型(前者是后者的子类型) var a: Int = 0;var b: Int? = 0;a = b; // ⇐ 不能将 Int? 赋值给 Intb = a; 不可变类型/可变类型 val 申明不可变变量,不可再赋值;var 申明可变变量,能再赋值。 var a = 0;val b = 1;a = b;b = a; // ⇐ 不能对 val 变量赋值字符串插值 val PI = 3.1415926val s1 = "PI is ${PI}"; // PI is 3.1415926val s2 = "PI is ${String.format("%.2f", PI)}"; // PI is 3.14字符串插值语法不反对设置格局(这点不如 C# 不便)对函数式编程的反对,一切都是表达式 ...

November 28, 2022 · 2 min · jiezi

关于kotlin:Kotlin协程Flow浅析

Kotlin协程中的Flow次要用于解决简单的异步数据,以一种”流“的形式,从上到下顺次解决,和RxJava的解决形式类型,然而比后者更加弱小。 Flow基本概念Flow中基本上有三个概念,即 发送方,解决中间层,接管方,能够类比水利发电站中的上游,发电站,上游的概念, 数据从上游开始发送”流淌“至两头站被”解决“了一下,又流淌到了上游。示例代码如下 flow { // 发送方、上游 emit(1) // 挂起函数,发送数据 emit(2) emit(3) emit(4) emit(5)}.filter { it > 2 } // 中转站,解决数据.map { it * 2 }.take(2).collect{ // 接管方,上游 println(it)}输入内容:68通过下面代码咱们能够看到,基于一种链式调用api的形式,流式的进行解决数据还是很棒的,接下来具体看一下下面的组成: flow{},是个高阶函数,次要用于创立一个新的Flow。在其Lambda函数外部应用了emit()挂起函数进行发送数据。filter{}、map{}、take{},属于两头解决层,也是两头数据处理的操作符,Flow最大的劣势,就是它的操作符跟汇合操作符高度一致。只有会用List、Sequence,那么就能够疾速上手 Flow 的操作符。collect{},上游接管方,也成为终止操作符,它的作用其实只有一个:终止Flow数据流,并且接管这些数据。其余创立Flow的形式还是flowOf()函数,示例代码如下 fun main() = runBlocking{aassssssssaaaaaaaas flowOf(1,2,3,4,5).filter { it > 2 } .map { it * 2 } .take(2) .collect{ println("flowof: $it") }}咱们在看一下list汇合的操作示例 listOf(1,2,3,4,5).filter { it > 2 } .map { it * 2 } .take(2) .forEach{ println("listof: $it") }通过以上比照发现,两者的基本操作简直统一,Kotlin也提供了两者互相转换的API,Flow.toList()、List.asFlow()这两个扩大函数,让数据在 List、Flow 之间来回转换,示例代码如下: ...

November 27, 2022 · 2 min · jiezi

关于kotlin:Kotlin协程Channel浅析

论断后行Kotlin协程中的Channel用于解决多个数据组合的流,随用随取,时刻筹备着,就像自来水一样,关上开关就有水了。 Channel应用示例fun main() = runBlocking { logX("开始") val channel = Channel<Int> { } launch { (1..3).forEach{ channel.send(it) logX("发送数据: $it") } // 敞开channel, 节俭资源 channel.close() } launch { for (i in channel){ logX("接收数据: $i") } } logX("完结")}示例代码 应用Channel创立了一组int类型的数据流,通过send发送数据,并通过for循环取出channel中的数据,最初channel是一种协程资源,应用完结后应该及时调用close办法敞开,免得节约不必要的资源。 Channel的源码public fun <E> Channel( capacity: Int = RENDEZVOUS, onBufferOverflow: BufferOverflow = BufferOverflow.SUSPEND, onUndeliveredElement: ((E) -> Unit)? = null): Channel<E> = when (capacity) { RENDEZVOUS -> {} CONFLATED -> {} UNLIMITED -> {} else -> {} }能够看到Channel的构造函数蕴含了三个参数,别离是capacity、onBufferOverflow、onUndeliveredElement. ...

November 23, 2022 · 2 min · jiezi

关于kotlin:Kotlin-Json-序列化

Kotlin能够间接调用 Java(也就能够间接应用 Jackson, Gson 等json库),不过我看到有 official 的序列化库,于是钻研了一下。 重点看了下多态的序列化,的确十分简洁,先上代码感受一下: @Serializablesealed interface Reply@Serializable@SerialName("text")class TextReply(val content: String): Reply@Serializable@SerialName("card")class CardReply(val content: String, val cardId: Long = 1L): Replyfun main() { val reply: Reply = CardReply("A card", 2L) // 序列化 val jsonString = Json.encodeToString(reply) println(jsonString) // 反序列化,隐式 val decodedReply: Reply = Json.decodeFromString(jsonString) println(decodedReply) // 显式 println( Json.decodeFromString<Reply>(jsonString) )}Output: {"type":"card","content":"A card","cardId":2}[email protected][email protected]CardReply & TextReply 实现了 Reply,能够看到序列化后果主动加上了类型标识"type": "card"。 再来看看泛型的序列化,同样非常简洁: fun main() { // 列表序列化 val jsonList = Json.encodeToString( listOf(CardReply("A card"), TextReply("A text")) ) println(jsonList) // 列表反序列化 val replies: List<Reply> = Json.decodeFromString(jsonList) println(replies)}Output: ...

October 27, 2022 · 1 min · jiezi

关于kotlin:微服务开发系列为什么选择-kotlin

我的项目中采纳的开发语言是 kotlin 。 开发人员能够依据本人须要采纳 java 语言开发,然而很显著的,我的项目中各种工具类曾经为了 kotlin 做出了很多批改,如果大量采纳 java 开发, 后果可能是比纯 java 开发的速度还要慢。 至于为什么要保持采纳 kotlin 开发,之前我有发表过一些文章来形容 kotlin 好用的中央,但还是在应用过程中总会时不时的被 kotlin 惊艳一下。 kotlin 除了齐全兼容 java 之外,还可能在架构中施展不少劣势,除了上面形容的中央,前面的介绍也会波及。 极少的代码量kotlin 将 java8 中的 stream 一系列的操作,都通过扩大个性,做了极大的简化。 例如 list 转 map users.associate { it.name to it},就省略了大堆繁琐的代码。 编写代码过程中的智能推断变量类型,可能帮忙你防止重复的推断类型,从而把本人绕晕。 对于传入匿名函数,可能防止手动创立函数对象。 对于空指针的 “?” 操作,可能极大简化对于空变量的判断解决。 等等,诸如此类的操作,如果可能齐全把握,就可能缩小数倍的代码量,学习过概率学的应该明确,更少的动作达到雷同的目标,天然产生问题的概率更小。 设计利器缩小代码量并不是 kotlin 的起点。 如果一个框架齐全由 kotlin 搭建,只利用其个性来督促个别开发者写出更好的业务代码就太节约了。 kotlin 还可能帮忙你补全框架设计中的一些遗憾。 异样抛出以框架设计中必不可少的业务异样抛出为例。 if (user.id.isNullOrEmpty()) { throw SomeException("user id cannot be empty")}这样的代码不可胜数,然而利用简略的扩大个性,就可能以新鲜并且正当的形式抛出异样。 fun Boolean.ifSome(message: String?) = throw SomeException(message)user.id.isNullOrEmpty().Boolean.ifSome("user id cannot be empty")这样除非在非凡状况下,否则框架中的任何中央都应用这种形式来抛出异样,即节俭代码,又领有更高的可读性。 ...

September 19, 2022 · 1 min · jiezi

关于kotlin:Kotlin协程解析系列上协程调度与挂起

vivo 互联网客户端团队- Ruan Wen本文是Kotlin协程解析系列文章的开篇,次要介绍Kotlin协程的创立、协程调度与协程挂起相干的内容 一、协程引入Kotlin 中引入 Coroutine(协程) 的概念,能够帮忙编写异步代码。 在应用和剖析协程前,首先要理解一下: 协程是什么? 为什么须要协程? 协程最为人称道的就是能够用看起来同步的形式写出异步的代码,极大进步了代码的可读性。在理论开发中最常见的异步操作莫过于网络申请。通常咱们须要通过各种回调的形式去解决网络申请,很容易就陷入到天堂回调中。 WalletHttp.target(VCoinTradeSubmitResult.class).setTag(tag) .setFullUrl(Constants.VCOIN_TRADE_SUBMIT_URL).setParams(params) .callback(new HttpCallback<VCoinTradeSubmitResult>() { @Override public void onSuccess(VCoinTradeSubmitResult vCoinTradeSubmitResult) { super.onSuccess(vCoinTradeSubmitResult); if (mView == null) { return; } //...... } }).post();上述示例是一个我的项目开发中常见的一个网络申请操作,通过接口回调的形式去获取网络申请后果。理论开发中也会常常遇到间断多个接口申请的状况,例如咱们我的项目中的集体核心页的逻辑就是先去异步获取。 本地缓存,获取失败的话就须要异步刷新一下账号token,而后网络申请相干集体核心的其余信息。这里简略举一个领取示例,进行领取时,可能要先去获取账号token,而后依赖该token再去做领取。 申请操作,依据领取返回数据再去查问领取后果,这种状况通过回调就可能演变为“天堂回调”。 //获取账号tokenWalletHttp.target(Account.class).setTag(tag) .setFullUrl(Constants.ACCOUNT_URL).setParams(params) .callback(new HttpCallback<Account>() { @Override public void onSuccess(Account account) { super.onSuccess(account); //依据账号token进行领取操作 WalletHttp.target(Pay.class).setFullUrl(Constants.PAY_URL).addToken(account.getToken()).callback(new HttpCallback<Pay>() { @Override public void onSuccess(Pay pay){ super.onSuccess(pay); //依据领取操作返回查问领取后果 WalletHttp.target(PayResult.class).setFullUrl(Constants.RESULT_URL).addResultCode(pay.getResultCode()).callback(new HttpCallback<PayResult>() { @Override public void onSuccess(PayResult result){ super.onSuccess(result); //...... } }).post(); } }).post(); } }).post();对于这种场景,kotlin协程“同步形式写出异步代码”的这个个性就能够很好的解决上述问题。若上述场景用kotlin 协程代码实现呢,可能就为: ...

August 16, 2022 · 21 min · jiezi

关于kotlin:Kotlin组件化-打造自己的AI语音助手

download:Kotlin+组件化 打造本人的AI语音助手Golang | 模块引入与疾速实现表格的读写业务介绍在很多管理系统下都有不少让后端进行表格进行操作的业务需要,本期就带大家了解一下Golang中如何使用模块引入的,以及讲解怎么疾速的使用excelize库,对表格进行读写创建的。注释配置模块引入环境咱们在期望在vscode终端中也可能使用模块引入,它是 Go 1.11后新版模块治理形式。go env -w GO111MODULE=auto复制代码其 GO111MODULE 可能传送: auto:在其外层且根目录里有 go.mod 文件时,则开启模块反对,否者无模块反对。 on:开启模块反对。 off:无模块反对。 而后,初始化这个我的项目,就会生成一个 go.mod 文件。go mod init excel-demo复制代码 go.mod 是Go 1.11版本引入的官网的包管理工具(之前为 gopath 来治理),它可能理解为前端开发中的 npm 的作用,次要是为理解决没有记录依赖包具体版本查阅艰巨的问题,也极大程度上便利了依赖包的治理。 引入excelize库excelize 是一个用于读写 Microsoft Excel™2007 及更高版本生成的电子表格文档(XLAM / XLSM / XLSX / XLTM / XLTX)的 Go 语言库,而且更新保护频繁且非常好用。引入excelizego get github.com/xuri/excelize/v2复制代码这里因为站点是国外的所以常常会因无法访问而超时。此时,不要慌,咱们换一个国内的代理就好了。go env -w GOPROXY=https://goproxy.cn复制代码创建表格package main import ( "fmt""github.com/xuri/excelize/v2") func createExcel(){ // 创建表格文件f := excelize.NewFile()// 在Sheet1设置A1项的值f.SetCellValue("Sheet1", "A1", "这是Sheet1的A1项")// 创建新的Sheet,命名为Sheet2selectIndex := f.NewSheet("Sheet2")// 在Sheet2设置B2项的值f.SetCellValue("Sheet2", "B2", "这是Sheet2的B2项")// 切换到Sheet2f.SetActiveSheet(selectIndex)// 保存文件if err := f.SaveAs("test.xlsx"); err != nil { fmt.Println(err)}} ...

July 23, 2022 · 2 min · jiezi

关于kotlin:从-Stream-到-Kotlin-再到-SPL

JAVA开发中常常会遇到不方便使用数据库,但又要进行结构化数据计算的场景。JAVA晚期没有提供相干类库,即便排序、分组这种根本计算也要硬写代码,开发效率很低。起初JAVA8推出了Stream库,凭借Lambda表达式、链式编程格调、汇合函数,才终于解决了结构化数据计算类库从无到有的问题。 Stream能够简化结构化数据的计算比方排序: Stream<Order> result=Orders.sorted((sAmount1,sAmount2)->Double.compare(sAmount1.Amount,sAmount2.Amount)).sorted((sClient1,sClient2)->CharSequence.compare(sClient2.Client,sClient1.Client));下面代码中的sorted是汇合函数,可不便地进行排序。"(参数)->函数体"的写法即Lambda表达式,能够简化匿名函数的定义。两个sorted函数连在一起用属于链式编程格调,能够使多步骤计算变得直观。 Stream计算能力还不够强依然以下面的排序为例,sorted函数只须要晓得排序字段和程序/逆序就够了,参考SQL的写法"…from Orders order by Client desc, Amount",但实际上还要额定输出排序字段的数据类型。程序/逆序用asc/desc(或+/-)等符号就能够简略示意了,但这里却要用compare函数。另外,理论要排序的字段程序和代码写进去的程序是相同的,有些反直觉。再比方分组汇总: Calendar cal=Calendar.getInstance();Map<Object, DoubleSummaryStatistics> c=Orders.collect(Collectors.groupingBy( r->{ cal.setTime(r.OrderDate); return cal.get(Calendar.YEAR)+"_"+r.SellerId; }, Collectors.summarizingDouble(r->{ return r.Amount; }) )); for(Object sellerid:c.keySet()){ DoubleSummaryStatistics r =c.get(sellerid); String year_sellerid[]=((String)sellerid).split("_"); System.out.println("group is (year):"+year_sellerid[0]+"\t (sellerid):"+year_sellerid[1]+"\t sum is:"+r.getSum()+"\t count is:"+r.getCount()); }下面代码中,所有呈现字段名的中央,都要先写上表名,即"表名.字段名",而不能像SQL那样省略表名。匿名函数语法简单,随着代码量的减少,复杂度迅速增长。两个匿名函数造成嵌套,代码更难解读。实现一个分组汇总性能要用多个函数和类,包含groupingBy、collect、Collectors、summarizingDouble、DoubleSummaryStatistics等,学习老本不低。分组汇总的后果是Map,而不是结构化数据类型,如果要持续计算,通常要定义新的结构化数据类型,并进行转换类型,处理过程很繁琐。两个分组字段在结构化数据计算中很常见,但函数grouping只反对一个分组变量,为了让一个变量代表两个字段,就要采取一些变通技巧,比方新建一个两字段的结构化数据类型,或者把两个字段用下划线拼起来,这让代码变得更加繁琐。 Stream计算能力有余,起因在于其根底语言JAVA是编译型语言,无奈提供业余的结构化数据对象,短少来自底层的无力反对。 JAVA是编译型语言,返回值的构造必须当时定义,遇到较多的两头步骤时,就要定义多个数据结构,这不仅让代码变得繁琐,还导致参数解决不灵便,要用一套简单的规定来实现匿名语法。解释性语言则人造反对动静构造,还能够不便地将参数表达式指定为值参数或函数参数,提供更简略的匿名函数。 在这种状况下,Kotlin应运而生。Kotlin是基于JAVA的古代开发语言,所谓古代,重点体现在对JAVA语法尤其是Stream的改良上,即Lambda表达式更加简洁,汇合函数更加丰盛。 Kotlin计算能力强于Stream比方排序: var resutl=Orders.sortedBy{it.Amount}.sortedByDescending{it.Client}下面代码毋庸指明排序字段的数据类型,毋庸用函数表白程序/逆序,间接援用it作为匿名函数的默认参数,而不是刻意定义,整体比Stream简短不少。 Kotlin改良并不大,计算能力依然有余依然以排序为例,Kotlin尽管提供了it这个默认参数,但实践上只有晓得字段名就够了,没必要带上表名(it)。排序函数只能对一个字段进行排序,不能动静接管多个字段。 再比方分组汇总: data class Grp(var OrderYear:Int,var SellerId:Int)data class Agg(var sumAmount: Double,var rowCount:Int)var result=Orders.groupingBy{Grp(it.OrderDate.year+1900,it.SellerId)} .fold(Agg(0.0,0),{ acc, elem -> Agg(acc.sumAmount + elem.Amount,acc.rowCount+1) }).toSortedMap(compareBy<Grp> { it. OrderYear}.thenBy { it. SellerId})result.forEach{println("group fields:${it.key.OrderYear}\t${it.key.SellerId}\t aggregate fields:${it.value.sumAmount}\t${it.value.rowCount}") }下面代码中,一个分组汇总的动作,须要用到多个函数,包含简单的嵌套函数。用到字段的中央要带上表名。分组汇总的后果不是结构化数据类型。要当时定义两头后果的数据结构。 ...

July 11, 2022 · 1 min · jiezi

关于kotlin:Android-Kotlin语言学习第一课基本知识

Android Kotlin语言学习第一课:基本知识一:Kotlin的类的定义(1)如果一个类容许被继承必须应用open关键字润饰(2)抽象类默认是open润饰抽象类简介 : 抽象类不能被实例化 , 在 class 关键字前应用 abstract 润饰 ;抽象类 , 默认应用 open 关键字润饰 , 能够间接继承 ;形象办法 , 默认应用 open 关键字润饰 , 能够间接 override 重写 ; 抽象类总结 :① 申明 : 抽象类中应用 abstract 申明 ;② 成员 : 抽象类中既能够定义失常属性和办法 , 又能够定义形象的属性和办法 ;③ 继承 : 抽象类能够继承抽象类 , 抽象类也能够继承失常类 , 失常类能够继承抽象类 ;④ 重写 : 抽象类中能够应用形象办法重写失常办法 , 也能够进行失常的办法重写 ;⑤ 特色 : 形象办法只能定义在抽象类中 , 失常类中不能有形象办法 ; /** * @author zhiqiangRuan * @ClassName * @Date 2022/6/8 */abstract class BaseActivity : AppCompatActivity() { /** * kotlin 容许一个类继承另一个类 * kotlin 所有的类都继承自Any类(Any 不是 java.lang.Object) * Any类是所有类的超类,对于没有超类型申明的类是默认超类 * Kotlin规定一个类能够给继承,必须应用open关键字润饰 * */ /** * 抽象类:关键字为abstract *形象函数: abstract fun initView() *形象属性:abstract var name:String */ /** *变量能够定义为可变(var)和不可变(val) * 常量定义:val相当于被final 润饰 var相当于可变非final润饰 *等价于Java:public static final String TAG=BaseActivity.class.getSimpleName()*/ //定义标记 val TAG: String = this.javaClass.simpleName //初始化布局View abstract fun initView() //初始化数据 abstract fun initData() //初始化获取布局id,带返回值的形象办法 abstract fun getLayoutId(): Int /** * 语法定义 * fun 办法名 (参数名 :参数类型):返回值类型{ * * return 返回值 * * } * * 无返回值能够应用Unit 代替返回值类型 ?代表可空 * Kotlin 是null平安的语言 Byte ,Short,Int ,Long型的变量都是不能承受null值,如果要存储null值须要应用Byte?,Short?,Int?,Long? * * override fun onCreate(savedInstanceState: Bundle?) :Unit{ * * } **/ override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(getLayoutId()) initView() initData() } override fun onDestroy() { super.onDestroy() }}二:变量和函数val(value的简写)用来申明一个不可变的变量,这种变量在初始赋值之后就再也不能从新赋值,对应Java中的final变量;var(variable的简写)用来申明一个可变的变量,这种变量在初始赋值会后依然能够再被从新赋值,对应Java中的非final变量; ...

June 9, 2022 · 4 min · jiezi

关于kotlin:KotlinKCP的应用第一篇

前言KCP的利用打算分两篇,本文是第一篇 本文次要记录从发现问题到应用KCP解决问题的折腾过程,下一篇记录KCP的利用 背景Kotlin 号称百分百兼容 Java ,所以在 Kotlin 中一些修饰符,比方 internal ,在编译后放在纯 Java 的我的项目中应用(没有Kotlin环境),Java 依然能够拜访被 internal 润饰的类、办法、字段等 在应用 Kotlin 开发过程中须要对外提供 SDK 包,在 SDK 中有一些 API 不想被内部调用,并且曾经增加了 internal 润饰,然而受限于上诉问题且第三方应用 SDK 的环境不可控(不能要求第三方必须应用Kotlin) 带着问题Google一番,查到以下几个解决方案: 应用 JvmName 注解设置一个不合乎 Java 命名规定的标识符1应用 在 Kotlin 中把一个不非法的标识符强行合法化1应用 JvmSynthetic 注解2以上计划能够满足大部分需要,然而以上计划都不满足暗藏构造方法,可能会想什么情景下须要暗藏构造方法,例如: class Builder(internal val a: Int, internal val b: Int) { /** * non-public constructor for java */ internal constructor() : this(-1, -1)}为此我还提了个Issue3,冀望官网把 JvmSynthetic 的作用域扩大到构造方法,不过官网如同没有打算实现 为解决暗藏构造方法,能够把构造方法私有化,对外裸露动态工厂办法: class Builder private constructor (internal val a: Int, internal val b: Int) { /** * non-public constructor for java */ private constructor() : this(-1, -1) companion object { @JvmStatic fun newBuilder(a: Int, b: Int) = Builder(a, b) }}解决方案说完了,大家散了吧,散了吧~ ...

May 10, 2022 · 5 min · jiezi

关于kotlin:Kotlin-高阶函数介绍

什么是高阶函数将函数作为参数或者返回值的,称高阶函数。 定义高阶函数action是一个高阶函数,(Int) -> Int示意是函数的类型,(Int)示意函数入参类型为Int,前面的Int示意函数返回类型。 private fun init() { val action: ((Int) -> Int) = {//函数进行加100运算 it + 100 } }函数作为参数以下代码,init函数调用doSomething函数,将Int类型 0 以及action函数传入doSomething。doSomething函数先对入参0进行加200运算,而后调用高阶函数action(进行加100运算),最初打印后果actionResult。 是不是有点策略设计模式的滋味?是的,齐全能够用它来实现策略设计模式。 private fun init() { val action: ((Int) -> Int) = {//函数进行加100运算 it + 100 } doSomething(0, action)//将0以及action传给doSomething } private fun doSomething(d: Int, action: (Int) -> Int) { val data = d + 200//先对d进行加200运算 val actionResult = action(data)//将加200后的后果传给action,后果保留在actionResult中 Log.e("test", "actionResult=${actionResult}")//打印后果 }函数作为返回值以下代码,依据不同的类型type,返回对应的action,接着对参数0进行运算,最初打印后果。 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val action = init("计划1") //获取到对应的action,传入参数0进行运算 val result = action?.invoke(0) //打印后果 Log.e("test", "result=${result}") } private fun init(type: String): ((Int) -> Int)? { val action1: ((Int) -> Int) = {//加100运算 it + 100 } val action2: ((Int) -> Int) = {//加200运算 it + 200 } //依据类型type,返回对应的action return when (type) { "计划1" -> action1 "计划2" -> action2 else -> null } }lamdba表达式也是高阶函数,只不过函数是匿名的。以下代码性能跟上述一样,只不过用amdba表达式代替了定义action函数。 ...

April 21, 2022 · 1 min · jiezi

关于kotlin:Kotlin扩展函数与扩展属性

扩大函数Kotlin扩大函数可能对⼀个类扩大新性能⽽⽆需继承该类或者使⽤像装璜者这样的设计模式。利用他能够缩小很多代码,晋升咱们的开发效率。 扩大函数的申明申明⼀个函数,而后让被扩大的类型作为函数的前缀就能够了,比方上面对TextView的扩大 fun TextView.setDrawableLeft(drawableId: Int?) { val drawable = ContextCompat.getDrawable(this.context, drawableId) if (drawable == null) { setCompoundDrawables( null, compoundDrawables[1], compoundDrawables[2], compoundDrawables[3] ) } else { drawable.apply { setBounds(0, 0, minimumWidth, minimumHeight) setCompoundDrawables( drawable, compoundDrawables[1], compoundDrawables[2], compoundDrawables[3] ) } }}而后咱们就能够应用TextView的实例调用setDrawableLeft()办法。尽管看上去如同咱们为TextView新增了一个办法,然而其实扩大是动态的,他并没有为扩大类型中插入新的办法 那么他是如何实现的呢,咱们反编译以下class文件,查看对应的java文件就明确了 扩大函数原理public static final void setDrawableLeft(@NotNull TextView $this$setDrawableLeft, @Nullable Integer drawableId){ //省略其余代码}原来是给咱们生成了一个对应的java静态方法,第一个参数就是接受者类型的对象,所以在办法外部能够拜访这个类中的成员。 既然是生成了java代码,那么这个办法就能够被其余java代码拜访 TextViewKt.setDrawableLeft(textview,drawableId)扩大属性和扩大函数相似,这种扩大也是动态的,并没有给原来的类增加新的属性 扩大属性的申明val StringBuilder.lastChar: String get() { if (this.isEmpty()) { return "" } return this.substring(length - 1) }申明形式和扩大函数也相似,须要一个接受者类型,在作用域类,this就代表这个接受者对象,因为这里lastChar咱们定义的是val,所以只用定义get()办法就能够了,如果是var类型,还须要定义set()办法,扩大字段的应用和失常字段一样。 ...

April 16, 2022 · 1 min · jiezi

关于kotlin:Kotlin对象比较注意点

背景现有一个StateFlow及其监听private val stateFlow = MutableStateFlow(kotlin.Pair<String, ArrayList<String>>("abc", ArrayList()))GlobalScope.launch { stateFlow.collect { // do something }}更新ArrayList并尝试emitGlobalScope.launch { stateFlow.value.second.add("test") stateFlow.emit(stateFlow.value)}实际上,collect并不会被调用 起因MutableStateFlow真正的实现者是StateFlowImpl, emit办法代码如下: override suspend fun emit(value: T) { this.value = value}查看value的set办法: public override var value: T get() = NULL.unbox(_state.value) set(value) { updateState(null, value ?: NULL) }private fun updateState(expectedState: Any?, newState: Any): Boolean { var curSequence = 0 var curSlots: Array<StateFlowSlot?>? = this.slots // benign race, we will not use it synchronized(this) { val oldState = _state.value if (expectedState != null && oldState != expectedState) return false // CAS support if (oldState == newState) return true // Don't do anything if value is not changing, but CAS -> true _state.value = newState curSequence = sequence ... 省略局部代码 }}其中"if (oldState == newState) return true"因emit前后是同一个对象,导致条件为true,那么,如果emit前后不是同一个对象,即可解决这个问题? ...

April 14, 2022 · 2 min · jiezi

关于kotlin:Kotlin语言基础入门到熟悉Lambda-表达式

什么是 Lambda 表达式?Lambda 表达式,其实就是匿名函数。而函数其实就是性能(function),匿名函数,就是匿名的性能代码了。在 Kotlin 当中,函数也是作为类型的一种呈现的,只管在以后的版本中,函数类型的灵活性还不如 Python 这样的语言,不过它也是能够被赋值和传递的,这次要就体现在 Lambda 表达式上。 咱们先来看一个 Lambda 表达式的例子: fun main(args: Array<String>) { val lambda = { left: Int, right: Int -> left + right } println(lambda(2, 3)) } 大家能够看到咱们定义了一个变量 lambda,赋值为一个 Lambda 表达式。Lambda 表达式用一对大括号括起来,前面先顺次写下参数及其类型,如果没有就不写,接着写下 -> ,这表明前面的是函数体了,函数体的最初一句的表达式后果就是 Lambda 表达式的返回值,比方这里的返回值就是参数求和的后果。 前面咱们用 () 的模式调用这个 Lambda 表达式,其实这个 () 对应的是 invoke 办法,换句话说,咱们在这里也能够这么写: println(lambda.invoke(2,3)) 这两种调用的写法是齐全等价的。 毫无疑问,这段代码的输入应该是 5。 简化 Lambda 表达式咱们再来看个例子: fun main(args: Array<String>) { args.forEach { if(it == "q") return println(it) } println("The End") } args 是一个数组,咱们曾经见过 for 循环迭代数组的例子,不过咱们其实有更现代化的伎俩来迭代一个数组,比方下面这个例子。这没什么可怕的,一旦撕下它的面具,你就会发现你早就意识它了: ...

February 18, 2022 · 4 min · jiezi

关于kotlin:官方回答来了Java-和-Kotlin-哪个是未来你想知道的都在这里

前言这几年,Google 大力发展基于 Kotlin 的 Androidx 库、Jetpack 库、Compose 库,很多新个性都是为 Kotlin 优化的。能够说,不懂 kotlin,今后在 Android 开发畛域规范库的倒退上将很受妨碍,Android 开发由 Java 转 Kotlin 早已势不可挡。 做 Android 的应该没有几个不晓得扔物线朱凯的,他是中国惟一的 Android GDE 和 Kotlin GDE(谷歌官网认证开发专家,这样的人在全世界仅 18 位),很多人的自定义 View 和 Kotlin 都是通过他的技术视频带进门的。凯哥的技术视频既轻松搞笑又浅显易懂,同时又有惊人的技术深度。 分享一下凯哥采访 Kotlin 和 Android 官网的视频! 凯哥跟 Android 和 Kotlin 官网聊了什么?灵魂拷问之一:Kotlin会被Android摈弃吗? 这个二货,居然当面问出如此犀利的问题!我也是醉了…… 那么,Kotlin 到底会被 Android 摈弃吗?Android 官网对此的回复是: 绝!对!不!会! 并且说道,Google 本人在外部也有 55 个 app 都曾经在用 Kotlin 开发了。而且这位 Google 大佬还跟凯哥走漏,Android 团队还会参加 Kotlin 的开发与决策过程。这么看来,Kotlin 真的是很平安了。 但……二货就是二货,他问了更狠的凯哥的问题没有最犀利,只有更犀利: 灵魂拷问之二:Java会被Android摈弃吗? 如此直白提问,除了光头扔物线,大略也没谁了吧…… 顺便也说一下 Android 官网对于这个问题的答复:Java 也是不会摈弃的,因为 Android 的零碎源码就是 Java 写的,没必要摈弃。但 Google 大佬和凯哥也都在视频里倡议,不要把「Android 抛不摈弃 Java 作为用不必 Kotlin 的判断根据」,因为 Kotlin 「是将来」。 ...

January 19, 2022 · 1 min · jiezi

关于kotlin:Kotlin之Flow实战

Flow异步流 意识 个性构建器和上下文启动勾销与勾销检测缓冲操作符 过渡操作符末端操作符组合展平异样 异样解决实现如何示意多个值?挂起函数能够异步的返回单个值,然而如何异步返回多个计算好的值呢? 计划 汇合序列挂起函数Flow用汇合,返回多个值,但不是异步的。 private fun createList() = listOf<Int>(1, 2, 3)@Testfun test_list() { createList().forEach { println(it) }}用序列,返回一个整数序列 private fun createSequence(): Sequence<Int> { return sequence { for (i in 1..3) { Thread.sleep(1000) // 伪装在计算,此处是阻塞,不能做其余事件了 // delay(1000) 这里不能用挂起函数 yield(i) } }}@Testfun test_sequence() { createSequence().forEach { println(it) }}看下源码 public fun <T> sequence(@BuilderInference block: suspend SequenceScope<T>.() -> Unit): Sequence<T> = Sequence { iterator(block) }传入的是一个SequenceScope的扩大函数。 @RestrictsSuspension@SinceKotlin("1.3")public abstract class SequenceScope<in T> internal constructor()而RestrictsSuspension限度只能应用外面提供的已有的挂起函数,如yield,yieldAll等。createSequence返回了多个值,然而也是同步的。 ...

January 5, 2022 · 8 min · jiezi

关于kotlin:Kotlin实战消除静态工具类顶层函数和属性

1.引入咱们都晓得, Java 作为 门面向对象的语言,须要所有的代码都写作类的函数。大多数状况下,这种形式还能行得通。但事实上,简直所有的大型项目,最终都有很多的代码并不能归属到任何 个类中。有时一个操作对应两个不同的类的对象,而且重要性相差无几。有时存在 个根本的对象,但你不想通过实例函数来增加操作,让它的 API 持续收缩。后果就是,最终这些类将不蕴含任何的状态或者实例函数,而是仅仅作为一堆动态函数的容器。在 JDK 中, 最适宜的例子应该就是 Collections了。看看你本人的代码,是不是也有一些类自身就以Util作为后缀命名。 在kotlin中,基本就不须要去创立这些无意义的类, 相同,能够把这些函数接放到代码文件的顶层,不必从属于任何的类。这些放在文件顶层的函数仍然是包内的成员,如果你须要从包外拜访它,则须要 import 但不再须要额定包一层。 2.顶层函数见名知意,原来在Java中,类处于顶层,类蕴含属性和办法,在Kotlin中,函数站在了类的地位,咱们能够间接把函数放在代码文件的顶层,让它不从属于任何类。就像上面这样,咱们在一个Test.kt文件中写入如下的Kotlin代码。 package com.smartcentury.agriculturalmarket.utilsfun getKotlin():String{ return "Kotlin"}当初咱们看一下如何在其余包中援用它: import com.smartcentury.agriculturalmarket.utils.getKotlingetKotlin()咱们只须要导入包,而后间接调用就能够了。 然而咱们可能会有个疑难,如果咱们想要在Java中调用这个办法应该如何调用呢? 在Java中调用Kotlin顶层函数。 要想晓得如何在Java中调用顶层函数其实很简略,咱们只有将Kotlin反编译一下就能够了。上面介绍下如何反编译Kotlin代码 。 第一步:在IDE中关上你须要查看反编译的代码文件,而后关上顶部的"Tools",抉择"Kotlin",再抉择"Show Kotlin ByteCode" 第二步:点击右侧“Decompile” 咱们会失去另外一个文件 通过以上的代码能够总结出两点内容: 顶层文件会反编译成一个容器类。(类名个别默认就是顶层文件名+"Kt"后缀,留神容器类名能够自定义)顶层函数会反编译成一个static动态函数,如代码中的getKotlin函数当初咱们应该晓得如何在java代码中如何调用了吧。 TestKt.getKotlin();可能有时候你感觉Kotlin为你主动生成的这个类名不好,那你能够通过@file:JvmName注解来自定义类名,就像上面这样。 @file:JvmName("MyKotlin")package com.smartcentury.agriculturalmarket.utils/** * @Author: Simon * @CreateDate: 2019/5/16 16:04 * @Description: */fun getKotlin():String{ return "Kotlin"}而且要留神,这个注解必须放在文件的结尾,包名的后面。 于是咱们在Java文件中能够这样调用 MyKotlin.getKotlin();3.顶层属性理解了顶层函数,上面再看看顶层属性。顶层属性也就是把属性间接放在文件顶层,不依附于类。咱们能够在顶层定义的属性包含var变量和val常量,就像上面这样。 @file:JvmName("MyKotlin")package com.smartcentury.agriculturalmarket.utils/** * @Author: Simon * @CreateDate: 2019/5/16 16:04 * @Description: */val name:String="kotlin"var type:String="language"用法和顶层办法一样,这里就不赘述了。 ...

December 3, 2021 · 1 min · jiezi

关于kotlin:Room-Kotlin-符号的处理

△ 图片来自 Unsplash 由 Marc Reichelt 提供 Jetpack Room 库在 SQLite 上提供了一个形象层,可能在没有任何样板代码的状况下,提供编译时验证 SQL 查问的能力。它通过解决代码注解和生成 Java 源代码的形式,实现上述行为。 注解处理器十分弱小,但它们会减少构建工夫。这对于用 Java 写的代码来说通常是能够承受的,但对于 Kotlin 而言,编译工夫耗费会非常明显,这是因为 Kotlin 没有一个内置的注解解决管道。相同,它通过 Kotlin 代码生成了存根 Java 代码来反对注解处理器,而后将其输送到 Java 编译器中进行解决。 因为并不是所有 Kotlin 源代码中的内容都能用 Java 示意,因而有些信息会在这种转换中失落。同样,Kotlin 是一种多平台语言,但 KAPT 只在面向 Java 字节码的状况下失效。 意识 Kotlin 符号解决随着注解处理器在 Android 上的宽泛应用,KAPT 成为了编译时的性能瓶颈。为了解决这个问题,Google Kotlin 编译器团队开始钻研一个代替计划,来为 Kotlin 提供一流的注解解决反对。当这个我的项目诞生之初,咱们十分冲动,因为它将帮忙 Room 更好地反对 Kotlin。从 Room 2.4 开始,它对 KSP 有了实验性的反对,咱们发现编译速度进步了 2 倍,特地是在全量编译的状况下。 本文内容重点不在注解的解决、Room 或者 KSP。而在于重点介绍咱们在为 Room 增加 KSP 反对时所面临的挑战和所做的衡量。为了了解本文您并不需要理解 Room 或者 KSP,但必须相熟注解解决。 ...

November 4, 2021 · 4 min · jiezi

关于kotlin:Android-app-中这样用flow更方便巧用flow实现polling

背景在app开发过程中,实现polling逻辑也是很常见的。当然在挪动端利用应用polling解决会影响利用的性能。比方polling解决减少了网络申请的次数,服务端压力减少。polling解决也耗费了更多的网络流量。然而利用polling的场景还是有的。有时是否抉择polling要思考很多综合的因素,比方咱们能够应用长连贯代替polling,然而长连贯在服务端和客户端的开发成本绝对要更高些,如果polling只是实现相似的跟帖等性能,咱们齐全能够应用polling实现,而不是抉择代价更高的长连贯计划。上面会分应用flow和不应用flow两种形式实现polling并比照两种形式的优缺点。 不应用flow咱们应用线程解决polling申请,首先咱们定义了一个polling thread。 class PollingThread: Thread() { override fun run() { var successBlock : (PollingData)->Unit = { Log.d("PollingThread","successBlock $it") } var failBlock:(Exception)->Unit ={ Log.d("PollingThread","failBlock $it") } while (isInterrupted) { pollingApi.call(successBlock, failBlock) Thread.sleep(5000) } } }在run办法中实现了polling接口的调用,并且接口的调用在while循环中。这里假如polling的工夫距离是5秒钟,所以这里调用线程的sleep办法暂停线程的执行,5秒后再次调用polling接口。polling接口的调用是异步过程,所以这里设置了两个回调,一个用于接管胜利的数据,一个用于接管失败的异样。如果在回调中更新了画面,咱们还要思考如何保障回调在ui线程执行,并且回调中不更新隐没的页面元素。 class PollingThread(val lifecycleOwner: LifecycleOwner): Thread() { override fun run() { var successBlock : (PollingData)->Unit = { Handler(Looper.getMainLooper()).post { if(lifecycleOwner.lifecycle.currentState >= Lifecycle.State.RESUMED) { Log.d("PollingThread", "successBlock $it") } } } var failBlock:(Exception)->Unit ={ Handler(Looper.getMainLooper()).post { if(lifecycleOwner.lifecycle.currentState >= Lifecycle.State.RESUMED) { Log.d("PollingThread", "failBlock $it") } } } while (isInterrupted) { pollingApi.call(successBlock, failBlock) Thread.sleep(5000) } } }这段代码减少了回调的线程切换和ui画面无效判断。应用Handler切换线程到ui线程,lifecycler判断ui画面的有效性。 ...

October 26, 2021 · 1 min · jiezi

关于kotlin:Android-app中这样用flow更方便刷新token获取数据

背景挪动app中展现的数据少数都是通过服务器接口获取的,当接口数据与用户相干时,服务端接口会要求客户端把用户信息通过接口发送到服务器。广泛的做法是把用户登录后的token数据发送给服务器的接口。思考到平安问题,token都有过期工夫,token过期后服务端就不能通过这个token查问用户的具体信息了。为了刷新过期token,服务端会提供一个刷新token的接口给客户端应用。 问题剖析因为要求上传token的服务端接口会有很多,所以这些接口的调用都须要思考token过期生效问题。这些接口调用的异样解决中须要减少token过期解决,在token过期的状况下触发token刷新解决。token刷新后触发接口的重试申请。如何应用flow实现 首先咱们实现一个刷新token的flow。 private val refreshTokenFlow = flow { if (expiredToken) { cachedToken = serverApi.refreshToken("token-0") expiredToken = false } emit(cachedToken) }expiredToken变量代表token是否过期,理论开发过程中这个变量的值应该依据过期工夫计算得出的。cachedToken变量保留着最新的token值,申请用户相干信息的接口时能够把这个token传递给服务端用于查问。咱们能够看到cachedToken的值是通过调用服务端提供的刷新接口获取的。这个flow最终发射的是最新的token值,同时咱们也看到这个flow调用刷新接口的逻辑只有token过期时才会被调用。第二步定义申请用户相干数据的flow private fun getDataFlow(token: String) = flow { emit(serverApi.getDataViaToken(token)) }因为申请用户数据的接口依赖token的值,所以这个flow是通过办法生成的。flow的生成也比较简单,它间接调用服务端的接口并将数据发射进来。 第三步将刷新token的flow和申请用户数据的flow开展 private val userDataFlow = refreshTokenFlow.flatMapConcat{token-> getDataFlow(token) }flatMapConcat办法将后面定义的两个流拼接在一起,这时咱们要是收集拼接后的userDataFlow,refreshTokenFlow会被收集,flatMapConcat办法接管到 refreshTokenFlow发射的token后开始收集getDataFlow办法返回的flow。这样连个flow的依赖关系通过flatMapConcat完满实现了。 第四步实现token过期重试机制 private val userDataFlow = refreshTokenFlow.flatMapConcat{token-> getDataFlow(token) }.retryWhen { cause, attempt -> if (attempt > 1) { false } else if(cause is InvalidTokenException) { expiredToken = true true }else{ false } }.catch { msgView.text = it.message }基于第三步的flow拼接咱们增加了retryWhen和cach两个块。retryWhen块用于实现重试机制,参数cause是后面流程产生的异样,参数attempt代表重试的次数,返回值true代表进行重试,返回值false代表不进行重试。在retryWhen块中咱们能够通过cause的类型来判断是否要重试,当cause为InvalidTokenException时代表token过期,所以进行重试并且重置了token过期expiredToken。为了防止有限地进行重试,这里限度重试次数为一次。catch块解决不进行重试时的逻辑,个别会将出错的信息显示到界面上。 ...

October 26, 2021 · 1 min · jiezi

关于kotlin:使用-Kotlin-Symbol-Processing-10-缩短-Kotlin-构建时间

作者 / 软件工程师 Ting-Yuan Huang 和 Jiaxiang Chen Kotlin Symbol Processing (KSP)——用于在 Kotlin 中构建轻量级编译器插件的全新工具现已推出稳固版本!其与 Kotlin 注解解决工具 (KAPT) 的性能类似,但速度进步了 2 倍,同时还能够间接拜访 Kotlin 语言构造并反对多个平台指标。 在过来的几个月里,KSP 共公布了 32 个版本,超过 162 个来自社区反馈的谬误问题被修复。如果您正期待着利用该工具,那当初是时候去尝试了。 为何要构建 KSP在 Android 团队中,咱们常常会向开发者提出这样一个问题: 就现阶段而言,开发利用时遇到的最大痛点是什么?其中呈现最频繁的问题就是构建速度。多年来,咱们始终在稳步优化 Android 构建工具链,当初咱们非常高兴可能通过 KSP 来实现这些优化。KSP 是应用 Kotlin 进行正文解决的新一代工具: 它将大幅提高 Kotlin 开发者的构建速度,而且不同于 KAPT,该工具提供了对 Kotlin/Native 和 Kotlin/JS 的反对。 为 Room 增加 KSP 反对不仅能晋升编译速度,还能让 Room 更好地了解 Kotlin 代码,比方应用 KAPT 无奈实现的泛型的可空性。KSP 还解锁了如生成 Kotlin 代码等全新可能性,这让 Room 在未来会有更棒的 Kotlin 用户体验。 -- Android 软件工程师 Yigit Boyar ...

October 8, 2021 · 1 min · jiezi

关于kotlin:Android中Handler的消息机制分析一

ps:浏览原文可获取 demo 源码,文章开端有原文链接 ps:源码是基于 android api 27 来剖析的,demo 是用 kotlin 语言写的。 Handler 是 Android 线程之间的音讯机制,次要的作用是将一个工作切换到指定的线程中去执行,与 Handler 一起协同工作的有 Looper、Message 和 MessageQueue;上面咱们以 Handler 在主线程解决音讯为例,对 Handler 发送音讯(实质上是将音讯插入链表)和解决音讯(顺便将音讯移除链表)相干的源码进行剖析。 咱们看一下 ActivityThread 中的 main 办法; public static void main(String[] args) { ...... //1、 Looper.prepareMainLooper(); ...... //2、 Looper.loop(); ......} 正文1 其实它外部是初始化 Looper 和 MessageQueue,咱们点击正文1 相干的代码看看; public static void prepareMainLooper() { //3、 prepare(false); ......} 咱们点击进去看看正文3 中的代码,也就是 Looper 的 prepare 办法; private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } //4、 sThreadLocal.set(new Looper(quitAllowed));} ...

September 19, 2021 · 5 min · jiezi

关于kotlin:Java-老兵不死Kotlin-蓄势待发

本文链接:https://www.oreilly.com/radar/where-programming-languages-are-headed-in-2020/ 作者:Zan McQuade & Amanda Quinn 编译:徐九在进入新的十年之际,各行各业都在进行盘点与瞻望。SegmentFault 作为开发者社区与科技行业的垂直媒体,始终关注行业的倒退与相干动静,近期已陆续为大家整顿了各大平台、社区针对技术畛域作出的预测与盘点。 明天,持续为大家粗译O'Reilly 公布的编程语言倒退瞻望 —— 《Where programming languages are headed in 2020》。该盘点及剖析由数位编程专家整顿得出,蕴含了大量他们对于某些经典编程语言以及新兴编程语言的思考以及基于行业的剖析。 Python 往年 Python 的最大新闻是,Python 之父吉多·范·罗苏姆(Guido van Rossum)正式退休,并将 Python 交给了 Python 领导委员会。到目前为止,这次势力转移并没有呈现“阵痛”,正如《Python Crash Course》的作者 Eric Matthes 所认为的那样,这是很失常的,因为“ Guido 在很长一段时间里仍将放弃本人在社区中的角色。” 此外,2020 年还将终止对 Python 2.7 的反对,这很可能导致保持应用 Python 2.7 的人变得很好受。 但不管怎样,Python 依然是数据迷信的首选语言。 对于 Matthes 而言,Python 令人兴奋的一个方面是“来自一个社区的各种乏味且要害的我的项目曾经诞生了,而社区曾经如此无意识地建设了这么长时间。” Python 领导委员会成员和 CPython 的外围开发人员 Carol Willing 也庆贺了这些我的项目,例如 Binder 服务,该服务通过在 Jupyter Notebook 中创立可执行环境来促成可反复的钻研,尤其是当它们超出其最后的指标时。 她指出,“活页夹去年在许多 Python 会议上被宽泛用于教学讲习班和教程。” Willing 还向 CircuitPython 和 Mu 我的项目大声疾呼,问道:“谁会不喜爱硬件呢,闪动的 LED、传感器,以及应用 Mu 的用户敌对的编辑器,这对成年人和孩子来说不都是很棒的抉择?” ...

September 7, 2021 · 2 min · jiezi

关于kotlin:Kotlin-coroutine-原理

CoroutinelifecycleScope.launch { Log.d("testCoroutineScope","testCoroutineScope start $this") delay(2000) Log.d("testCoroutineScope","testCoroutineScope middle1") delay(2000) Log.d("testCoroutineScope","testCoroutineScope middle2") delay(2000) Log.d("testCoroutineScope","testCoroutineScope end") }上边的代码展现了启动协程的办法,通常在协程体中会调用到suspend函数。咱们都理解kotlin中协程的反对除了利用到kotlin的一些语法个性,同时针对协程还进行了编译器的批改,使得咱们在应用协程时更加直观不便。然而这也带来了另一个问题,咱们更难了解协程的具体工作细节。上面咱们从最让人费解的协程体开始动手。 一、摸索协程体到底是什么?这里认为通过launch、async启动的block块就是协程体。 协程体在通过编译器编译后会生成一个新的对象,具体对象的实现是什么样的呢?看看上面反编译后的代码与原代码的比拟: //原来的kotlin代码private fun testCoroutineScope() { val block: suspend CoroutineScope.() -> Unit = { Log.d("testCoroutineScope", "testCoroutineScope start") delay(2000) Log.d("testCoroutineScope", "testCoroutineScope end") } lifecycleScope.launch(block = block) }为了不便察看,我把协程体独自定义一个block变量。kotlin的协程体只是简略的调用delay挂起办法并在办法调用前后增加了log。 //反编译后失去的代码private final void testCoroutineScope() { Function2 block = (Function2)(new Function2((Continuation)null) { int label; @Nullable public final Object invokeSuspend(@NotNull Object $result) { Object var2 = IntrinsicsKt.getCOROUTINE_SUSPENDED(); switch(this.label) { case 0: ResultKt.throwOnFailure($result); Log.d("testCoroutineScope", "testCoroutineScope start"); this.label = 1; if (DelayKt.delay(2000L, this) == var2) { return var2; } break; case 1: ResultKt.throwOnFailure($result); break; default: throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine"); } Log.d("testCoroutineScope", "testCoroutineScope end"); return Unit.INSTANCE; } @NotNull public final Continuation create(@Nullable Object value, @NotNull Continuation completion) { Intrinsics.checkNotNullParameter(completion, "completion"); Function2 var3 = new <anonymous constructor>(completion); return var3; } public final Object invoke(Object var1, Object var2) { return ((<undefinedtype>)this.create(var1, (Continuation)var2)).invokeSuspend(Unit.INSTANCE); } }); BuildersKt.launch$default((CoroutineScope)LifecycleOwnerKt.getLifecycleScope(this), (CoroutineContext)null, (CoroutineStart)null, block, 3, (Object)null); }通过反编译后的协程体是一个实现Function2接口类型的对象,Function2反对两个形参的invoke办法。除了invoke办法还有create和invokeSuspend两个办法,所以协程体更精确的形容应该是实现了Function2接口的对象。反编译的代码能够帮咱们理解大体的思路,然而一些细节还是有问题的。咱们在网上搜寻对于协程体对象的介绍,介绍中说协程体是SuspendLambda类的子类。那么它真的是SuspendLambda的子类吗?咱们能够批改代码简略验证下: ...

September 6, 2021 · 6 min · jiezi

关于kotlin:Kotlin组件化-打造自己的AI语音助手

Kotlin+组件化 打造本人的AI语音助手一.Kotlin数组 kotlin为数组减少了一个Array类,为元素是根本类型的数组减少了xxArray类(其中xx也就是Byte,Short, Int等根本类型)Kotlin创立数组大抵有如下两种形式: 1.应用arrayOf(), arrayOfNulls(),emptyArray()工具函数。 2.应用Array(size: Int, init:(Int) -> T) 首先先介绍第一种 Array第二种用到了函数的常识,原本想到函数的到前面函数那个章节在讲,不过怕忘了,就先简略的说说吧。 Array(size: Int, init: (Int) -> T) 第一个参数就是对数组设置的大小很好了解。那么第二个参数是什么。 其实在kotlin里中参数也能够定义某个办法的类型的。哇,感觉很神奇吧!咱们在写java的时候基本上就是参数要不传一般类型要不就是对象类型,没有据说过能够传办法类型的。 因为在kotlin里中办法其实也是有类型的。所以第二个参数 init:(Int) -> T 代表这这个办法返回的类型是T只能有一个参数类型是Int型。尽管没有看源码,然而从它的字面是就能够看出这个参数其实就是对array的每个索引进行初始化的。Int就是该array的所对应的索引。上面看一下这个代码: 看过我以前的文章的敌人应该晓得这个it代表什么了吧,就是代表(Int)的参数传入的值,也就是array的下标的索引。arrayInit的后果就是每个下标的索引所对应的值为下标索引 * 2, arrayInitTwo下标索引对应的值就是索引值。在接下来的Kotlin值函数的文章中我会具体讲讲kotlin函数的用法。 其实有些敌人兴许会有这样的疑虑,为什么在写数组的时候有的时候须要指定泛型,有的时候不须要呢。其实你记住一点就能够了,在初始化的时候如果你是曾经将参数写进去了,kotlin用自动识别的就不须要指定泛型了,如果只是指定大小没有写入参数的话。因为kotlin不晓得须要什么类型,所以须要指定泛型。kotlin还提供了一个emptyArray()函数,用法基本一致,这种形式创立了一个长度为0的空数组。 如果仔细的敌人应该留神到,我在写kotlin数组的时候,取值或者赋值也用到了get,set办法。所以koltin中不只有汇合能够用,数组也能够用。 遍历数组用 for in就好。 kotlin里数组提供了很多工具办法,例如 asList() 将该数组转成list的汇合。 arr.all({it > 20}) 判断是否数组里的值都大于20,如果是返回true,不是返回false arr.any({it > 20})判断是否数组里的值其中有一个大于20,如果是返回true,不是返回false 依据数组元素来计算k, var arrMap = arr.associate({it + 2 to it + 10}) 将数组arr的第5个元素(包含)到底7个元素(不包含)赋值为1 arr.fill(1, 4, 6) 还有很多工具办法,能够去kotlin官网查看,在这里我就不一一列举啦。还有多维数组,跟java的多维数组一样。 2.Kotlin汇合 kotlin汇合类同样有两个接口派生:Collection和Map。但Kotlin的联合被分成两个大类,可变汇合和不可变汇合。只有可变汇合才能够增加批改,删除等解决操作。不可变汇合只能读取元素。 上图为kotlin提供的汇合,通过上图能够看出kotlin的汇合实现类比java更少,他只是提供了HashSet, LinkedHashSet, ArrayList这三个常见的实现类,如果开发者须要应用TreeSet, LinkedList汇合实现类仍然能够应用java汇合框架提供的类。 纵观Kotlin汇合体系,不难发现kotlin只提供了HashSet,HashMap, LinkedHashSet, LinkedHashMap, ArrayList这5个汇合实现类,而且他们都是可变汇合,那么说好的不可变汇合呢。kotlin的不可变汇合类并没有裸露进去,咱们只能通过函数来创立不可变汇合。 ...

August 29, 2021 · 1 min · jiezi

关于kotlin:Kotlin-高阶函数第一行代码-Kotlin-学习笔记

高阶函数详解从本章的 Kotlin 课堂起,咱们就将辞别基础知识,开始转向 Kotlin 的高级用法,从而进一步晋升你的 Kotlin 程度。 那么就从高阶函数开始吧。 定义高阶函数高阶函数和 Lambda 的关系是密不可分的。在第 2 章疾速入门 Kotlin 编程的时候,咱们曾经学习了 Lambda 编程的基础知识,并且把握了一些与汇合相干的函数式 API 的用法,如 map、filter 函数等。另外,在第 3 章的 Kotlin 课堂中,咱们又学习了 Kotlin 的规范函数,如 run、apply 函数等。 你有没有发现,这几个函数有一个独特的特点:它们都会要求咱们传入一个 Lambda 表达式作为参数。像这种接管 Lambda 参数的函数就能够称为具备函数式编程格调的 API,而如果你想要定义本人的函数式 API,那就得借助高阶函数来实现了,这也是咱们本节 Kotlin 课堂所要重点学习的内容。 首先来看一下高阶函数的定义。如果一个函数接管另一个函数作为参数,或者返回值的类型是另一个函数,那么该函数就称为高阶函数。 这个定义可能有点不太好了解,一个函数怎么能接管另一个函数作为参数呢?这就波及另外一个概念了:函数类型。咱们晓得,编程语言中有整型、布尔型等字段类型,而 Kotlin 又减少了一个函数类型的概念。如果咱们将这种函数类型增加到一个函数的参数申明或者返回值申明当中,那么这就是一个高阶函数了。 接下来咱们就学习一下如何定义一个函数类型。不同于定义一个一般的字段类型,函数类型的语法规定是有点非凡的,根本规定如下: (String, Int) -> Unit忽然看到这样的语法规定,你肯定一头雾水吧?不过不必放心,急躁听完我的解释之后,你就可能轻松了解了。 既然是定义一个函数类型,那么最要害的就是要申明该函数接管什么参数,以及它的返回值是什么。因而,-> 右边的局部就是用来申明该函数接管什么参数的,多个参数之间应用逗号隔开,如果不接管任何参数,写一对空括号就能够了。而 -> 左边的局部用于申明该函数的返回值是什么类型,如果没有返回值就应用 Unit,它大抵相当于 Java 中的 void。 当初将上述函数类型增加到某个函数的参数申明或者返回值申明上,那么这个函数就是一个高阶函数了,如下所示: fun example(func: (String, Int) -> Unit) { func("hello", 123)}能够看到,这里的 example() 函数接管了一个函数类型的参数,因而 example() 函数就是一个高阶函数。而调用一个函数类型的参数,它的语法相似于调用一个一般的函数,只须要在参数名的前面加上一对括号,并在括号中传入必要的参数即可。 ...

July 26, 2021 · 4 min · jiezi

关于kotlin:Kotlin-扩展函数和运算符重载第一行代码-Kotlin-学习笔记

扩大函数和运算符重载不少古代高级编程语言中有扩大函数这个概念,Java 却始终以来都不反对这个十分有用的性能,这多少会让人有些遗憾。但值得快乐的是,Kotlin 对扩大函数进行了很好的反对,因而这个知识点是咱们无论如何都不能错过的。 大有用处的扩大函数首先看一下什么是扩大函数。扩大函数示意即便在不批改某个类的源码的状况下,依然能够关上这个类,向该类增加新的函数。 为了帮忙你更好地了解,咱们先来思考一个性能。一段字符串中可能蕴含字母、数字和特殊符号等字符,当初咱们心愿统计字符串中字母的数量,你要怎么实现这个性能呢?如果依照个别的编程思维,可能大多数人会很天然地写出如下函数: object StringUtil { fun letterCount(str: String) : Int { var count = 0 for (char in str) { if (char.isLetter()) { count ++ } } return count } }这里先定义了一个 StringUtil 单例类,而后在这个单例类中定义了一个 lettersCount() 函数,该函数接管一个字符串参数。在 lettersCount() 办法中,咱们应用 for-in 循环去遍历字符串中的每一个字符。如果该字符是一个字母的话,那么就将计数器加 1,最终返回计数器的值。 当初,当咱们须要统计某个字符串中的字母数量时,只须要编写如下代码即可: val str = "ABC123xyz!@#"val count = StringUtil.lettersCount(str)这种写法相对能够失常工作,并且这也是 Java 编程中最规范的实现思维。然而有了扩大函数之后就不一样了,咱们能够应用一种更加面向对象的思维来实现这个性能,比如说将 lettersCount() 函数增加到 String 类当中。 上面咱们先来学习一下定义扩大函数的语法结构,其实非常简单,如下所示: fun ClassName.methodName(param1: Int, param2: Int): Int { return 0}相比于定义一个一般的函数,定义扩大函数只须要在函数名的后面加上一个 ClassName. 的语法结构,就示意将该函数增加到指定类当中了。 ...

July 25, 2021 · 3 min · jiezi

关于kotlin:Kotlin-延迟初始化和密封类第一行代码-Kotlin-学习笔记

theme: fancy highlight: a11y-dark提早初始化和密封类本节的 Kotlin 课堂,咱们就来学习提早初始化和密封类这两局部内容。 对变量缩短初始化后面咱们曾经学习了 Kotlin 语言的许多个性,包含变量不可变,变量不可为空,等等。这些个性都是为了尽可能地保障程序平安而设计的,然而有些时候这些个性也会在编码时给咱们带来不少的麻烦。 比方,如果你的类中存在很多全局变量实例,为了保障它们可能满足 Kotlin 的空指针查看语法规范,你不得不做许多的非空判断爱护才行,即便你十分确定它们不会为空。 上面咱们通过一个具体的例子来看一下吧,就应用刚刚的 UIBestPractice 我的项目来作为例子。如果你仔细观察 MainActivity 中的代码,会发现这里适配器的写法稍微有点非凡: class MainActivity : AppCompatActivity(), View.OnClickListener { private var adapter: MsgAdapter? = null override fun onCreate(savedInstanceState: Bundle?) { ... adapter = MsgAdapter(msgList) ... } override fun onClick(v: View?) { ... adapter?.notifyItemInserted(msgList.size - 1) ... } }这里咱们将 adapter 设置为了全局变量,然而它的初始化工作是在 onCreate() 办法中进行的,因而不得不先将 adapter 赋值为 null,同时把它的类型申明成 MsgAdapter?。 尽管咱们会在 onCreate() 办法中对 adapter 进行初始化,同时能确保 onClick() 办法必然在 onCreate() 办法之后才会调用,然而咱们在 onClick() 办法中调用 adapter 的任何办法时依然要进行判空解决才行,否则编译必定无奈通过。 ...

July 24, 2021 · 3 min · jiezi

关于kotlin:Kotlin-标准函数和静态方法第一行代码-Kotlin-学习笔记

规范函数和静态方法学完了 Kotlin 的基础知识而已,明天咱们来学习 Kotlin 的规范函数和静态方法。 规范函数 with、run 和 applyKotlin 的规范函数指的是 Standard.kt 文件中定义的函数,任何 Kotlin 代码都能够自在地调用所有的规范函数。 在 疾速入门 kotlin 编程 中,咱们曾经学习了 let 这个规范函数,它的次要作用就是配合 ?. 操作符来进行辅助判空解决,这里就不再赘述了。 with 规范函数with 函数接管两个参数:第一个参数能够是一个任意类型的对象,第二个参数是一个 Lambda 表达式。with 函数会在 Lambda 表达式中提供第一个参数对象的上下文,并应用 Lambda 表达式中的最初一行代码作为返回值返回。示例代码如下: val result = with(obj) { // 这里是 obj 的上下文 "value" // with 函数的返回值}那么这个函数有什么作用呢?它能够在间断调用同一个对象的多个办法时让代码变得更加精简,上面咱们来看一个具体的例子。 比方有一个水果列表,当初咱们想吃完所有水果,并将后果打印进去,就能够这样写: val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape")val builder = StringBuilder()builder.append("Start eating fruits.\n")for (fruit in list) { builder.append(fruit).append("\n")}builder.append("Ate all fruits.")val result = builder.toString()println(result)仔细观察上述代码,你会发现咱们间断调用了很屡次 builder 对象的办法。其实这个时候就能够思考应用 with 函数来让代码变得更加精简,如下所示: ...

July 23, 2021 · 3 min · jiezi

关于kotlin:快速入门-kotlin-编程第一行代码-Kotlin-学习笔记

疾速入门 Kotlin 编程面向对象编程不同于面向过程的语言(比方 C 语言),面向对象的语言是能够创立类的。类就是对事物的一种封装。 简略概括一下,就是将事物封装成具体的类,而后将事物所领有的属性和能力别离定义成类中的字段和函数,接下来对类进行实例化,再依据具体的编程需要调用类中的字段和办法即可。 类与对象class Person { var name = "" var age = 0 fun eat() { println(name + " is eating. He is " + age + " years old.") }}val p = Person()Kotlin 中也是应用 class 关键字来申明一个类的应用 var 关键字创立了 name 和 age 这两个字段,这是因为咱们须要在创建对象之后再指定具体的姓名和年龄,而如果应用 val 关键字的话,初始化之后就不能再从新赋值了Kotlin 中实例化一个类的形式和 Java 是根本相似的,只是去掉了 new 关键字而已继承与构造函数能够让 Student 类去继承 Person 类,这样 Student 就主动领有了 Person 中的字段和函数,另外还能够定义本人独有的字段和函数。想要让 Student 类继承 Person 类,咱们得做两件事才行 在 Person 类的后面加上 open 关键字使其能够被继承在 Java 中继承的关键字是 extends,而在 Kotlin 中变成了一个冒号 ...

July 22, 2021 · 7 min · jiezi

关于kotlin:从-LiveData-迁移到-Kotlin-数据流

LiveData 的历史要追溯到 2017 年。彼时,观察者模式无效简化了开发,但诸如 RxJava 一类的库对老手而言有些太过简单。为此,架构组件团队打造了 LiveData: 一个专用于 Android 的具备自主生命周期感知能力的可察看的数据存储器类。LiveData 被无意简化设计,这使得开发者很容易上手;而对于较为简单的交互数据流场景,建议您应用 RxJava,这样两者联合的劣势就施展进去了。 DeadData?LiveData 对于 Java 开发者、初学者或是一些简略场景而言仍是可行的解决方案。而对于一些其余的场景,更好的抉择是应用 Kotlin 数据流 (Kotlin Flow)。虽说数据流 (相较 LiveData) 有更平缓的学习曲线,但因为它是 JetBrains 力挺的 Kotlin 语言的一部分,且 Jetpack Compose 正式版行将公布,故两者配合更能施展出 Kotlin 数据流中响应式模型的后劲。 此前一段时间,咱们探讨了 如何应用 Kotlin 数据流 来连贯您的利用当中除了视图和 View Model 以外的其余局部。而当初咱们有了 一种更平安的形式来从 Android 的界面中取得数据流,曾经能够创作一份残缺的迁徙指南了。 在这篇文章中,您将学到如何把数据流裸露给视图、如何收集数据流,以及如何通过调优来适应不同的需要。 数据流: 把简略复杂化,又把简单变简略LiveData 就做了一件事并且做得不错: 它在 缓存最新的数据 和感知 Android 中的生命周期的同时将数据裸露了进去。稍后咱们会理解到 LiveData 还能够 启动协程 和 创立简单的数据转换,这可能会须要花点工夫。 接下来咱们一起比拟 LiveData 和 Kotlin 数据流中绝对应的写法吧: #1: 应用可变数据存储器裸露一次性操作的后果 这是一个经典的操作模式,其中您会应用协程的后果来扭转状态容器: △ 将一次性操作的后果裸露给可变的数据容器 (LiveData) ...

June 29, 2021 · 4 min · jiezi

关于kotlin:FAQ-使用-Kotlin-进行-Android-开发

自从 2017 年咱们发表反对 Kotlin 以来,收到了很多对于应用 Kotlin 进行 Android 开发的问题: 大家想晓得当初是否适宜学习 Kotlin,是否要在利用开发中引入 Kotlin,学习 Kotlin 的最佳课程或教程是什么,Google 外部是否在应用 Kotlin,以及咱们对 Java 编程语言的布局是怎么的?本文将一一作答。 问: 是否应该学习 Kotlin 进行 Android 开发?最常提及的问题大都围绕同一个话题: "对于初学者,应该抉择学习 Kotlin 还是 Java 编程语言?""如果曾经把握了 Java 基础知识,当初适宜改用 Kotlin 进行 Android 开发吗?""对于资深 Java 开发者如果学习 Android 开发,举荐间接上手 Kotlin 还是应用 Java 入门呢?"简略来说: 是的!开始学习和应用 Kotlin 吧! 开展来答复: Kotlin 与 Android2017 年,咱们在 Google I/O 大会上发表反对 Kotlin。从那时起,咱们开始着手确保咱们的 API、文档和示例实用于 Kotlin。2019 年,Kotlin 成为 Android 开发的首选语言,这让咱们开始更加依赖于 Kotlin 的性能。例如,协程成为咱们实现异步操作的举荐计划。 咱们还做了以下工作: Kotlin 优先库 首先在若干 Android Jetpack API (如 Room、LiveData、ViewModel 和 WorkManager) 中,咱们减少了对 Kotlin 协程的一流反对,从而转变了在 Android 上执行异步操作的形式。Firebase Android SDK 和许多 Jetpack 库都具备 Kotlin 扩大库 (KTX),通过 Kotlin 应用起来更加晦涩。 ...

June 23, 2021 · 2 min · jiezi

关于kotlin:Kotlin-中使用-Hilt-的开发实践

Hilt 是基于 Dagger 开发的全新的依赖项注入代码库,它简化了 Android 利用中 Dagger 的调用形式。本文通过简短的代码片段为您展现其外围性能以帮忙开发者们疾速入门 Hilt。 配置 Hilt如需在利用中配置 Hilt,请先参考 Gradle Build Setup。 实现装置全副的依赖和插件当前,仅需在您的 Application 类之前增加 @HiltAndroidApp 注解即可开始应用 Hilt,而无需其它操作。 @HiltAndroidAppclass App : Application()定义并且注入依赖项当您写代码用到依赖项注入的时候,有两个要点须要思考: 您须要注入依赖项的类;能够作为依赖项进行注入的类。而上述这两点并不互斥,而且在很多状况下,您的类既能够注入依赖项同时也蕴含依赖。 使依赖项可注入 如果须要在 Hilt 中使某个类变得可注入,您须要通知 Hilt 如何创立该类的实例。该过程叫做绑定 (bindings)。 在 Hilt 中定义绑定有三种形式: 在构造函数上增加 @Inject 注解;在模块上应用 @Binds 注解;在模块上应用 @Provides 注解。⮕ 在构造函数上应用 @Inject 注解 任何类的构造函数都能够增加 @Inject 注解,这样该类在整个工程中都能够作为依赖进行注入。 class OatMilk @Inject constructor() { ... }⮕ 应用模块 在 Hilt 中另外两种将类转为可注入的办法是应用模块。 Hilt 模块 就如同 "菜谱",它能够通知 Hilt 如何创立那些不具备构造函数的类的实例,比方接口或者零碎服务。 此外,在您的测试中,任何模块都能够被其它模块所代替。这有利于应用 mock 替换接口实现。 模块通过 @InstallIn 注解被装置在特定的 Hilt 组件 中。这一部分我会在前面具体介绍。 ...

June 4, 2021 · 3 min · jiezi

关于kotlin:使用-Kotlin-提高生产力

Kotlin 以其简洁的个性而闻名,而在咱们的实际中,更加简洁就意味着更加高效。事实上,在应用 Kotlin 的业余 Android 开发者中,有多达 67% 的人示意 Kotlin 曾经帮忙他们晋升了生产力。在接下来的内容中,我会分享一些 Kotlin 帮忙咱们的合作伙伴工程师们进步生产力的形式,并为您介绍有助于此的 Kotlin 性能。 在应用 Kotlin 的业余 Android 开发者中,有多达 67% 的人示意 Kotlin 曾经帮忙他们晋升了生产力 简洁、简略且高效Kotlin 的简洁性对开发的各个阶段都有影响: 作为代码作者: 您能够专一于须要解决的问题 (而不是语法)。更少的代码意味着更少地测试、更少地调试以及更少写出 Bug 的机会。作为审阅和维护者: 您须要浏览的代码变少了,从而更容易了解代码的作用,也因而更容易审阅和保护代码。以下例子来自 Flipkart 的团队: "在一次外部考察中,50% 的开发人员提到,对于应用 Kotlin 编写的模块,预估实现性能所需的工夫会有所缩小。" ——Flipkart Kotlin 的性能与生产力因为 Kotlin 的简洁与高可读性,大多数 Kotlin 的性能都能够进步生产力。上面让咱们来看一些最罕用的性能。 默认参数与构建器在 Java 编程语言中,当您的构造函数中的某些参数是可选参数时,您通常会采纳上面两种办法之一: 增加多个构造函数;实现 构建器模式。在应用 Kotlin 时,因为默认参数性能的存在,您无需应用这两种办法。默认参数使您无需额定的样板代码便能实现函数重载。 对 Kotlin 的应用使得 Cash App 团队能够革除诸多构建器,从而缩小了他们须要编写的代码量。在某些状况下,代码量被缩小了 25% 之多。 举个例子,上面的代码是一个 Task 对象别离应用构建器及默认参数的实现形式。该 Task 惟一的必须参数是工作名 (name): /* Copyright 2020 Google LLC. SPDX-License-Identifier: Apache-2.0 */3- public class Task {- private final String name;- private final Date deadline;- private final TaskPriority priority;- private final boolean completed;-- private Task(String name, Date deadline, TaskPriority priority, boolean completed) {- this.name = name;- this.deadline = deadline;- this.priority = priority;- this.completed = completed;- }-- public static class Builder {- private final String name;- private Date deadline;- private TaskPriority priority;- private boolean completed;-- public Builder(String name) {- this.name = name;- }-- public Builder setDeadline(Date deadline) {- this.deadline = deadline;- return this;- }-- public Builder setPriority(TaskPriority priority) {- this.priority = priority;- return this;- }-- public Builder setCompleted(boolean completed) {- this.completed = completed;- return this;- }-- public Task build() {- return new Task(name, deadline, priority, completed);- }- }-}+ data class Task(+ val name: String,+ val deadline: Date = DEFAULT_DEADLINE,+ val priority: TaskPriority = TaskPriority.LOW,+ val completed: Boolean = false+)您能够通过咱们的这篇 Kotlin Vocabulary | Kotlin 默认参数 理解无关默认参数的更多信息。 ...

May 6, 2021 · 2 min · jiezi

关于kotlin:关于Kotlin中日志的使用方法

1 引言想必学过Java的人都晓得一个@Slf4j应用得如许的难受: @Slf4jpublic class TestController{ @GetMapping("/test") public String test(){ log.debug("debug"); return "test"; }}然而很可怜在Kotlin中并没有这种注解,因而,本文给出了一种相似@Slf4j注解在Kotlin中的应用办法,以及介绍一个100%应用Kotlin编写的日志库。 2 入手写@Slf4j很简略,先上代码: import org.slf4j.Loggerimport org.slf4j.LoggerFactory@Target(AnnotationTarget.CLASS)@Retention(AnnotationRetention.RUNTIME)annotation class Slf4j{ companion object{ val <reified T> T.log: Logger inline get() = LoggerFactory.getLogger(T::class.java) }}逐行解释如下: @Target:与Java中的@Target相似,注解的指标,这里是类@Retention:与Java中的@Retention相似,运行时保留annotation class:申明一个注解companion object:伴生对象val <reified T> T.log:Logger:申明一个Logger类型的泛型对象inline get() = LoggerFactory.getLogger(T::class.java):申明getter为内联,申明为内联能力应用T,这样能力传递给前面的getLogger,T::class.java相当于Java中的T.class,也就是getLogger(T::class.java)相当于getLogger(SomeClass.class)应用很简略: @RestController@Slf4jclass TestController { @GetMapping("/test") fun test():String{ log.warn("cc") return "test" }}间接类上加一个注解,就能够应用log.info/log.warn之类的办法了。 3 kotlin-logging下面介绍了注解的应用办法,如果不想应用注解的话,能够应用他人的库,比方kotlin-logging。 kotlin-logging是一个100%应用Kotlin编写的轻度封装了slf4j的开源日志库,曾经播种1.4k的star: 依赖如下: <dependency> <groupId>io.github.microutils</groupId> <artifactId>kotlin-logging-jvm</artifactId> <version>2.0.6</version></dependency>Gradle: implementation 'io.github.microutils:kotlin-logging-jvm:2.0.6'引入时,只须要在对应的类中创立一个属性即可: private val logger = KotlinLogging.logger {}应用时,间接调用其中的info/debug/error等即可: import mu.KotlinLoggingprivate val logger = KotlinLogging.logger {} class FooWithLogging { val message = "world" fun bar() { logger.debug { "hello $message" } }}4 两者联合应用当然,也能够将注解与kotlin-logging联合一下应用,首先,笔者简略地看了一下KotlinLogging的接口: ...

March 17, 2021 · 1 min · jiezi

关于kotlin:kotlin语言中的out和in

ps:浏览原文,能够获取源码 在 kotlin 语言中,out 示意协变,in 示意逆变;协变和逆变并不是 kotlin 独有的概念,像 Java、C#都有这样的概念;为了可能了解 kotlin 语言中的 out 和 in,咱们先用 Java 的泛型来举例,咱们须要用泛型,是因为它的益处就是在编译的时候可能查看类型平安,并且所有的强制转换都是主动和隐式的。 1、Java 中的 ? extends T 和 ? super T 1、1 ? extends T ps:代码是在 AndroidStudio 工具上写的 建设一个 Java 文件鸟类 Birds; public class Birds { private String name; public Birds(String name) { this.name = name; } public void flight() { System.out.println("我是" + name + ",属于鸟类,我能航行"); }}建设一个 Java 文件乌鸦类 Crow 并继承 Birds; public class Crow extends Birds { public Crow(String name) { super(name); }}新建一个 Java 文件的泛型类 TestBirds 并限度泛型 T 是 Birds 的子类; ...

March 14, 2021 · 4 min · jiezi

关于kotlin:kotlin语言中的out和in

在 kotlin 语言中,out 示意协变,in 示意逆变;协变和逆变并不是 kotlin 独有的概念,像 Java、C#都有这样的概念;为了可能了解 kotlin 语言中的 out 和 in,咱们先用 Java 的泛型来举例,咱们须要用泛型,是因为它的益处就是在编译的时候可能查看类型平安,并且所有的强制转换都是主动和隐式的。 1、Java 中的 ? extends T 和 ? super T 1、1 ? extends T ps:代码是在 AndroidStudio 工具上写的 建设一个 Java 文件鸟类 Birds; public class Birds { private String name; public Birds(String name) { this.name = name; } public void flight() { System.out.println("我是" + name + ",属于鸟类,我能航行"); }}建设一个 Java 文件乌鸦类 Crow 并继承 Birds; public class Crow extends Birds { public Crow(String name) { super(name); }}新建一个 Java 文件的泛型类 TestBirds 并限度泛型 T 是 Birds 的子类; ...

March 14, 2021 · 4 min · jiezi

关于kotlin:kotlin语言的基础语法

这是我微信公众号的一篇文章,这里转载分享一下。

March 8, 2021 · 1 min · jiezi

关于kotlin:开始切换到-Kotlin-谷歌工程师给初学者的知识点总结

在 2019 年的 I/O 大会上,咱们曾发表 Kotlin 将会是 Android 利用开发的首选语言,然而,局部开发者们反馈仍不分明如何切换到 Kotlin,如果团队中没有人相熟 Kotlin,一开始间接应用 Kotlin 进行我的项目开发还是会令人生畏。 在 Android Studio Profiler 团队外部,咱们是通过几个步骤克服了这个问题,第一步是要求所有的单元测试应用 Kotlin 编写。这么做无效防止了咱们犯的任何渺小谬误间接影响到生产环境中的代码,因为单元测试与生产环境的代码是离开的。 我收集了咱们团队在历次 Code Review 中遇到过的常见问题并整顿出了这篇文章,心愿这篇文章对宽广 Android 社区的敌人们有所帮忙。 留神: 本文的指标读者是 Kotlin 的初学者,如果您的团队曾经纯熟应用 Kotlin 进行我的项目开发,本文对您的帮忙可能不大。但如果您感觉咱们脱漏了一些应该被提及的内容,请在本文留言区留言通知咱们。IDE 性能: 把 Java 文件转换成 Kotlin 文件如果您应用 Android Studio 开发程序,学习 Kotlin 的最简略办法是应用 Java 语言编写单元测试,而后在Android Studio 的菜单栏中点击 Code -> Convert Java File to Kotlin File 按钮将 Java 文件转换成 Kotlin 文件。 这个操作可能会提醒您 "Some code in the rest of your project may require corrections after performing this conversion. Do you want to find such code and correct it too?",它的意思是说我的项目中的其余代码可能会受到此次转换的影响,而且有可能会导致谬误,请问是否须要定位出错的代码,并对相干代码进行批改。我倡议抉择 "No",这样您就能够将代码的批改集中在一个文件上。 ...

December 5, 2020 · 4 min · jiezi

关于kotlin:大众点评用-Kotlin-打造灵活稳定兼备的应用-Android-开发者故事

https://www.bilibili.com/vide... 公众点评是寰球最早的生产点评网站之一,成立于 2003 年。进入挪动互联网时代后,用户能够在手机上应用公众点评 APP 不便地查问任何一个城市里的餐厅、影院、商场、景点和酒店等信息,并且理解其余用户写下的评估。利用也会根据用户评估数据和专家评估来推出各种榜单,比方 "必系列" 榜单和 "黑珍珠" 系列餐厅评估体系,还能依据用户的爱好为其在信息流中举荐可能感兴趣的餐厅和景点等信息。 △ "必系列" 榜单 △ "黑珍珠" 系列餐厅评估体系 为了保障用户良好的应用体验和继续迭代新的性能,利用稳定性和开发效率是点评技术团队关注的重中之重。 "点评 Android 利用的开发合作模式是壳工程依赖于一系列根底和业务组件,利用到 Kotlin 的局部扩散在十余支业务团队,近四十个业务仓库中,涵盖了首页、商户页、直播、榜单等外围业务。"—— 程康阳,Android 开发工程师 Kotlin 现代化的语言个性,比方扩大函数和 lambda 表达式,帮忙团队缩小了近 30% 的代码量,晋升了近 20% 的需要开发效率。也因而,目前点评团队曾经有 15% 左右的依赖库在应用 Kotlin 进行开发和保护。 △ Kotlin 扩大函数 Kotlin 另一个让开发团队拍案叫绝的性能是空安全性,这和 Kotlin 与 Java 良好的互操作性也有关系——只须要在 Java 代码中写好 @Nullable 和 @NonNull 等注解,就能确保 Kotlin 代码取得正确的可空性推断。如此便捷弱小的空平安个性也帮忙团队将利用的 NPE 从日均 3 个升高至 0。 △ 在 Java 代码中应用空平安注解能够确保 Kotlin 代码取得正确的可空性推断 ...

December 5, 2020 · 1 min · jiezi

关于kotlin:Kotlin-Android-Extensions-的未来计划

作者 / 产品经理 David Winer Android Kotlin Extensions Gradle 插件 (请勿与 Android KTX 混同) 公布于 2017 年,为应用 Kotlin 进行 Android 开发带来了两项新的便当性能: Synthetic 视图 : 您能够将调用 findViewById 替换为应用 kotlinx.android.synthetic 进行 UI 交互。@Parcelize 注解: 帮忙您移除样板代码并通过 @Parcelize 注解轻松创立 Parcelable。咱们随后公布了 实用于 Android 的视图绑定 组件,它是一个与 Android 构建工具链深度集成并提供与 Kotlin synthetic 相似性能的官网反对库。咱们尽管仍举荐应用 Parcelize,但 Kotlin synthetic 却存在一些弊病: 净化全局命名空间不能裸露可空性信息仅反对 Kotlin 代码Android Kotlin Extensions 插件最后由 JetBrains 开发,咱们也独特探讨了持续保留 synthetic 的利弊: 咱们尽力确保在可行范畴内对 API 的长期反对,但咱们也心愿为开发者提供领导,帮忙开发者保护衰弱的代码库并最终博得用户的称心。 在接下来的一年里,咱们的团队将独特弃用 synthetics,并持续反对咱们倡议的选项——"视图绑定 (View Binding)"。这意味着: ...

December 4, 2020 · 1 min · jiezi

关于kotlin:Kotlin-Vocabulary-揭秘协程中的-suspend-修饰符

Kotlin 协程把 suspend 修饰符引入到了咱们 Android 开发者的日常开发中。您是否好奇它的底层工作原理呢?编译器是如何转换咱们的代码,使其可能挂起和复原协程操作的呢? 理解这些将会帮您更好地了解挂起函数 (suspend function) 为什么只会在所有工作实现后才会返回,以及如何在不阻塞线程的状况下挂起代码。 本文概要: Kotlin 编译器将会为每个挂起函数创立一个状态机,这个状态机将为咱们治理协程的操作! ???? 如果您是 Android 平台上协程的初学者,请查阅上面这些协程 codelab: 在 Android 利用中应用协程协程的进阶应用: Kotlin Flow 和 Live Data协程 101协程简化了 Android 平台的异步操作。正如官网文档 《利用 Kotlin 协程晋升利用性能》 所介绍的,咱们能够应用协程治理那些以往可能阻塞主线程或者让利用卡死的异步工作。 协程也能够帮咱们用命令式代码替换那些基于回调的 API。例如,上面这段应用了回调的异步代码: // 简化的只思考了根底性能的代码fun loginUser(userId: String, password: String, userResult: Callback<User>) { // 异步回调 userRemoteDataSource.logUserIn { user -> // 胜利的网络申请 userLocalDataSource.logUserIn(user) { userDb -> // 保留后果到数据库 userResult.success(userDb) } }}下面的回调能够通过应用协程转换为顺序调用: suspend fun loginUser(userId: String, password: String): User { val user = userRemoteDataSource.logUserIn(userId, password) val userDb = userLocalDataSource.logUserIn(user) return userDb}在前面这段代码中,咱们为函数增加了 suspend 修饰符,它能够通知编译器,该函数须要在协程中执行。作为开发者,您能够把挂起函数看作是一般函数,只不过它可能会在某些时刻挂起和复原而已。 ...

December 2, 2020 · 4 min · jiezi

关于kotlin:Kotlin-Vocabulary-内联类-inline-class

*特定条件和状况这篇博客形容了一个 Kotlin 试验性功能,它还在调整之中。本文基于 Kotlin 1.3.50 撰写。类型平安帮忙咱们防止出现谬误以及防止回过头去调试谬误。对于 Android 资源文件,比方 String、Font 或 Animation 资源,咱们能够应用 androidx.annotations,通过应用像 @StringRes、@FontRes 这样的注解,就能够让代码查看工具 (如 Lint) 限度咱们只能传递正确类型的参数: fun myStringResUsage(@StringRes string: Int){ } // 谬误: 须要 String 类型的资源myStringResUsage(1)扩大浏览: 利用正文改良代码查看如果咱们的 ID 对应的不是 Android 资源,而是 Doggo 或 Cat 之类的域对象,那么就会很难辨别这两个同为 Int 类型的 ID。为了实现类型平安,须要将 ID 包装在一个类中,从而使狗与猫的 ID 编码为不同的类型。这样做的毛病是您要付出额定的性能老本,因为原本只须要一个原生类型,然而却实例化进去了一个新的对象。 通过 Kotlin 内联类 您能够创立包装类型 (wrapper type),却不会有额定的性能耗费。这是 Kotlin 1.3 中增加的试验性功能。内联类只能有一个属性。在编译时,内联类会在可能的中央被替换为其外部的属性 (勾销装箱),从而升高惯例包装类的性能老本。对于包装对象是原生类型的状况,这尤其重要,因为编译器曾经对它们进行了优化。所以将一个原始数据类型包装在内联类里就意味着,在可能的状况下,数据值会以原始数据值的模式呈现。 inline class DoggoId(val id: Long)data class Doggo(val id: DoggoId, … ) // 用法val goodDoggo = Doggo(DoggoId(doggoId), …)fun pet(id: DoggoId) { … }}内联内联类的惟一作用是成为某种类型的包装,因而 Kotlin 对其施加了许多限度: ...

November 29, 2020 · 3 min · jiezi

关于kotlin:在-Android-开发中使用协程-代码实战

本文是介绍 Android 协程系列中的第三局部,这篇文章通过发送一次性申请来介绍如何应用协程解决在理论编码过程中遇到的问题。在浏览本文之前,建议您先浏览本系列的前两篇文章,对于在 Android 开发中应用协程的 背景介绍 和 上手指南。 应用协程解决理论编码问题前两篇文章次要是介绍了如何应用协程来简化代码,在 Android 上保障主线程平安,防止工作透露。以此为背景,咱们认为应用协程是在解决后台任务和简化 Android 回调代码的绝佳计划。 目前为止,咱们次要集中在介绍协程是什么,以及如何治理它们,本文咱们将介绍如何应用协程来实现一些理论工作。协程同函数一样,是在编程语言个性中的一个罕用个性,您能够应用它来实现任何能够通过函数和对象能实现的性能。然而,在理论编程中,始终存在两种类型的工作非常适合应用协程来解决: 一次性申请 (one shot requests) 是那种调用一下就申请一下,申请获取到后果后就完结执行;流式申请 (streaming request) 在发出请求后,还始终监听它的变动并返回给调用方,在拿到第一个后果之后它们也不会完结。协程对于解决这些工作是一个绝佳的解决方案。在这篇文章中,咱们将会深刻介绍一次性申请,并摸索如何在 Android 中应用协程实现它们。 一次性申请一次性申请会调用一次就申请一次,获取到后果后就完结执行。这个模式同调用惯例函数很像 —— 调用一次,执行,而后返回。正因为同函数调用类似,所以绝对于流式申请它更容易了解。 一次性申请会调用一次就申请一次,获取到后果后就完结执行。 举例来说,您能够把它类比为浏览器加载页面。当您点击了这篇文章的链接后,浏览器向服务器发送了网络申请,而后进行页面加载。一旦页面数据传输到浏览器后,浏览器就有了所有须要的数据,而后进行同后端服务的对话。如果服务器起初又批改了这篇文章的内容,新的更改是不会显示在浏览器中的,除非您被动刷新了浏览器页面。 只管这样的形式短少了流式申请那样的实时推送个性,然而它还是十分有用的。在 Android 的利用中您能够用这种形式解决很多问题,比方对数据的查问、存储或更新,它还很实用于解决列表排序问题。 问题: 展现一个有序列表咱们通过一个展现有序列表的例子来摸索一下如何构建一次性申请。为了让例子更具体一些,咱们来构建一个用于商店员工应用的库存利用,应用它可能依据上次进货的工夫来查找相应商品,并可能以升序和降序的形式排列。因为这个仓库中存储的商品很多,所以对它们进行排序要花费将近 1 秒钟,因而咱们须要应用协程来防止阻塞主线程。 在利用中,所有的数据都会存储到 Room 数据库中。因为不波及到网络申请,因而咱们不须要进行网络申请,从而专一于一次性申请这样的编程模式。因为无需进行网络申请,这个例子会很简略,尽管如此它依然展现了该应用怎么的模式来实现一次性申请。 为了应用协程来实现此需要,您须要在协程中引入 ViewModel、Repository 和 Dao。让咱们一一进行介绍,看看如何把它们同协程整合在一起。 class ProductsViewModel(val productsRepository: ProductsRepository): ViewModel() { private val _sortedProducts = MutableLiveData<List<ProductListing>>() val sortedProducts: LiveData<List<ProductListing>> = _sortedProducts /** * 当用户点击相应排序按钮后,UI 进行调用 */ fun onSortAscending() = sortPricesBy(ascending = true) fun onSortDescending() = sortPricesBy(ascending = false) private fun sortPricesBy(ascending: Boolean) { viewModelScope.launch { // suspend 和 resume 使得这个数据库申请是主线程平安的,所以 ViewModel 不须要关怀线程平安问题 _sortedProducts.value = productsRepository.loadSortedProducts(ascending) } }}ProductsViewModel 负责从 UI 层承受事件,而后向 repository 申请更新的数据。它应用 LiveData 来存储以后排序的列表数据,以供 UI 进行展现。当呈现某个新事件时,sortProductsBy 会启动一个新的协程对列表进行排序,当排序实现后更新 LiveData。在这种架构下,通常都是应用 ViewModel 启动协程,因为这样做的话能够在 onCleared 中勾销所启动的协程。当用户来到此界面后,这些工作就没必要持续进行了。 ...

November 28, 2020 · 4 min · jiezi

关于kotlin:Kotlin-Vocabulary-枚举和-R8-编译器

学习或应用一门新的编程语言时,理解这门语言所提供的性能,以及理解这些性能是否有相关联的开销,都是非常重要的环节。 这方面的问题在 Kotlin 中显得更加乏味,因为 Kotlin 最终会编译为 Java 字节码,然而它却提供了 Java 所没有的性能。那么 Kotlin 是怎么做到的呢?这些性能有没有额定开销?如果有,咱们能做些什么来优化它吗? 接下来的内容与 Kotlin 中枚举 (enums) 和 when 语句 (java 中的 switch 语句) 无关。我会探讨一些和 when 语句相干的潜在开销,以及 Android R8 编译器是如何优化您的利用并缩小这些开销的。 编译器首先,咱们讲一讲 D8 和 R8。 事实上,有三个编译器参加了 Android 利用中 Kotlin 代码的编译。 1. Kotlin 编译器 Kotlin 编译器将会首先运行,它会把您写的代码转换为 Java 字节码。尽管听起来很棒,但惋惜的是 Android 设施上并不运行 Java 字节码,而是被称为 DEX 的 Dalvik 可执行文件。Dalvik 是 Android 最后所应用的运行时。而 Android 当初的运行时,则是从 Android 5.0 Lollipop 开始应用的 ART (Android Runtime),不过 ART 仍然在运行 DEX 代码 (如果替换后的运行时无奈运行原有的可执行文件的话,就毫无兼容性可言了)。 ...

November 27, 2020 · 2 min · jiezi

关于kotlin:在-Android-开发中使用协程-上手指南

本文是介绍 Android 协程系列中的第二局部,这篇文章次要会介绍如何应用协程来解决工作,并且能在工作开始执行后放弃对它的追踪。 放弃对协程的追踪本系列文章的第一篇,咱们探讨了协程适宜用来解决哪些问题。这里再简略回顾一下,协程适宜解决以下两个常见的编程问题: 解决耗时工作 (Long running tasks),这种工作经常会阻塞住主线程;保障主线程平安 (Main-safety) ,即确保安全地从主线程调用任何 suspend 函数。协程通过在惯例函数之上减少 suspend 和 resume 两个操作来解决上述问题。当某个特定的线程上的所有协程被 suspend 后,该线程便可腾出资源去解决其余工作。 协程本身并不可能追踪正在解决的工作,然而有成千盈百个协程并对它们同时执行挂起操作并没有太大问题。协程是轻量级的,但解决的工作却不肯定是轻量的,比方读取文件或者发送网络申请。 应用代码来手动追踪上千个协程是十分艰难的,您能够尝试对所有协程进行跟踪,手动确保它们都实现了或者都被勾销了,那么代码会臃肿且易出错。如果代码不是很完满,就会失去对协程的追踪,也就是所谓 "work leak" 的状况。 工作透露 (work leak) 是指某个协程失落无奈追踪,它相似于内存透露,但比它更加蹩脚,这样失落的协程能够复原本人,从而占用内存、CPU、磁盘资源,甚至会发动一个网络申请,而这也意味着它所占用的这些资源都无奈失去重用。 透露协程会节约内存、CPU、磁盘资源,甚至发送一个无用的网络申请。 为了可能防止协程透露,Kotlin 引入了 结构化并发 (structured concurrency) 机制,它是一系列编程语言个性和实际指南的联合,遵循它能帮忙您追踪到所有运行于协程中的工作。 在 Android 平台上,咱们能够应用结构化并发来做到以下三件事: 勾销工作 —— 当某项工作不再须要时勾销它;追踪工作 —— 当工作正在执行时,追踪它;收回谬误信号 —— 当协程失败时,收回谬误信号表明有谬误产生。接下来咱们对以上几点一一进行探讨,看看结构化并发是如何帮忙可能追踪所有协程,而不会导致透露呈现的。 借助 scope 来勾销工作在 Kotlin 中,定义协程必须指定其 CoroutineScope 。CoroutineScope 能够对协程进行追踪,即便协程被挂起也是如此。同 第一篇文章 中讲到的调度程序 (Dispatcher) 不同,CoroutineScope 并不运行协程,它只是确保您不会失去对协程的追踪。 为了确保所有的协程都会被追踪,Kotlin 不容许在没有应用 CoroutineScope 的状况下启动新的协程。CoroutineScope 可被看作是一个具备超能力的 ExecutorService 的轻量级版本。它能启动新的协程,同时这个协程还具备咱们在第一局部所说的 suspend 和 resume 的劣势。 ...

November 26, 2020 · 3 min · jiezi

关于kotlin:网易云音乐的-Kotlin-乐章-Android-开发者故事

https://www.bilibili.com/vide... "音乐是灵魂之间的美妙交换,是带着情绪的艺术品。网易云音乐要做的,就是帮忙用户发现和分享好音乐,用音乐连贯用户和音乐人,让用户去感触音乐人想表白的情绪,让更多的人用音乐取暖、发光、取得力量。"—— 郭元,网易云音乐产品经理 网易云音乐是网易旗下一款专一于发现和分享的音乐产品,依靠业余音乐人、DJ、好友举荐及社区性能,为用户打造全新的音乐生存。目前,网易云音乐用户数已超过 8 亿,曲库数超 4,000 万 (近期更新数据),入驻原创音乐人超 20 万,是中国最沉闷的音乐社区和中国最大的原创音乐平台。 △ 用网易云音乐和好友分享音乐 Android 客户端开发团队 2019 年 8 月引入 Kotlin 之后,很快就发现学习 Kotlin 是一件比拟轻松的事件: 刚开始的一段时间,常常能够在团队成员的周报中看到对 Kotlin 个性的探讨,团队中也不时会有共事撰写 Kotlin 的学习总结文章并发进去分享。大家根本都能够很快上手开发。而且通过 Kotlin 官方网站、Github 上 Kotlin 我的项目中的文档,以及 Android Studio 提供的将 Kotlin 代码反编译为 Java 代码的性能,都能够帮忙团队成员们更加深刻地理解 Kotlin 语言。 "Kotlin 作为 Android 开发的新语言新技术,集成了很多其它语言中的先进设计思维。与 Java 代码兼容和相互调用的个性,也极大地缩小了咱们在外部推广 Kotlin 的阻力。"—— 贾斌,网易云音乐资深 Android 开发工程师 目前在网易云音乐的 Android 工程中,Kotlin 文件比例大概占 23%,而且新增的性能大部分都是应用 Kotlin 进行编写。团队也同时引入了 KTX 和协程等库来进步开发效率,让工程师更专一于性能自身的实现。 应用 Kotlin 带来的第一个直观益处是简洁。团队本人有做过统计: ...

November 26, 2020 · 1 min · jiezi

关于kotlin:Kotlin-Vocabulary-类型别名-typealias

作者 / David Winer, Kotlin 产品经理 有时候一些可读性差、不够明确或者名字太长的类型申明会烦扰代码的 "自我表白"。这种状况下,能够应用 Kotlin 特地针对这个问题提供的个性: Typealias (本文下称 "类型别名")。类型别名能够使您在不减少新类型的状况下,为现有类或函数类型提供代替名称。 类型别名的应用应用类型别名为函数类型命名: typealias TeardownLogic = () -> Unitfun onCancel(teardown : TeardownLogic){ }private typealias OnDoggoClick = (dog: Pet.GoodDoggo) -> Unitval onClick: OnDoggoClick不过要留神这种用法会暗藏传入参数,使可读性变差: typealias TeardownLogic = () -> Unittypealias TeardownLogic = (exception: Exception) -> Unitfun onCancel(teardown : TeardownLogic){ // 无奈轻易通晓能够从 TeardownLogic 失去什么信息}类型别名有助于缩短较长的泛型类名: typealias Doggos = List<Pet.GoodDoggo>fun train(dogs: Doggos){ ... }应用类型别名时,须要思考是否有必要这么做: 在这里应用类型别名真的会让您的代码意义更明确、可读性更好吗? 思考一下,应用类型别名是否使您的代码变得更易懂 如果您正应用的某个类名称很长,您能够应用类型别名来缩短它: typealias AVD = AnimatedVectorDrawable在此示例中,应用 导入别名 (import alias) 会更加适合: ...

November 25, 2020 · 1 min · jiezi

关于kotlin:Kotlin-Vocabulary-密封类-sealed-class

咱们常常须要在代码中申明一些无限汇合,如: 网络申请可能为胜利或失败;用户账户是高级用户或普通用户。 咱们能够应用枚举来实现这类模型,但枚举本身存在许多限度。枚举类型的每个值只容许有一个实例,同时枚举也无奈为每个类型增加额定信息,例如,您无奈为枚举中的 "Error" 增加相干的 Exception 类型数据。 当然也能够应用一个抽象类而后让一些类继承它,这样就能够随便扩大,但这会失去枚举所带来的无限汇合的劣势。而 sealed class (本文下称 "密封类" ) 则同时蕴含了后面两者的劣势 —— 抽象类示意的灵活性和枚举里汇合的受限性。持续浏览接下来的内容能够帮忙大家更加深刻地理解密封类,您也能够点击观看 视频。 密封类的根本应用和抽象类相似,密封类可用于示意层级关系。子类能够是任意的类: 数据类、Kotlin 对象、一般的类,甚至也能够是另一个密封类。但不同于抽象类的是,您必须把层级申明在同一文件中,或者嵌套在类的外部。 // Result.ktsealed class Result<out T : Any> { data class Success<out T : Any>(val data: T) : Result<T>() data class Error(val exception: Exception) : Result<Nothing>()}尝试在密封类所定义的文件外继承类 (内部继承),则会导致编译谬误: Cannot access ‘<init>’: it is private in Result遗记了一个分支?在 when 语句中,咱们经常须要解决所有可能的类型: when(result) { is Result.Success -> { } is Result.Error -> { }}然而如果有人为 Result 类增加了一个新的类型: InProgress: ...

November 24, 2020 · 2 min · jiezi

关于kotlin:Kotlin-Vocabulary-Collection-和-Sequence

在很多场景中咱们会应用到汇合,Kotlin 规范库 (Kotlin Standard Library) 中提供了十分多杰出的对于汇合的实用函数。其中,Kotlin 提供了基于不同执行形式的两种汇合类型: 立刻执行 (eagerly) 的 Collection 类型,提早执行 (lazily) 的 Sequence 类型。本篇文章将向您介绍两者的区别,并向您介绍这两种类型别离该在哪种状况下应用,以及它们的性能体现。获取更多相干信息能够查看如下视频: https://www.bilibili.com/vide... Collection 和 Sequence 的比照立刻执行和提早执行的区别在于每次对汇合进行转换时,这个操作会在何时真正执行。 Collection (也称汇合) 是在每次操作时立刻执行的,执行后果会存储到一个新的汇合中。作用于 Collection 的转换操作是 内联函数。例如,map 的实现形式,能够看到它是一个创立了新 ArrayList 的内联函数: public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> { return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)}Sequence (也称序列) 是提早执行的,它有两种类型: 两头操作 (intermediate) 和末端操作 (terminal)。两头操作不会立刻执行,它们只是被存储起来,仅当末端操作被调用时,才会依照程序在每个元素上执行两头操作,而后执行末端操作。两头操作 (比方 map、distinct、groupBy 等) 会返回另一个Sequence,而末端操作 (比方 first、toList、count 等) 则不会。 Sequence 是不会保留对汇合我的项目的援用的。它基于原始汇合的迭代器 (iterator) 创立,并且保留要执行的所有两头操作的援用。 与在 Collection 中执行转换操作不同,Sequence 执行的两头转换不是内联函数,因为内联函数无奈存储,而 Sequence 须要存储它们。咱们能够通过下列代码看到像 map 这样的两头操作是如何实现的,能够看到转换函数会存储在一个新的 Sequence 实例中: ...

November 21, 2020 · 2 min · jiezi

关于kotlin:算法-Notes|LeetCode-14-最长公共前缀-easy

前言对于算法,集体感觉,有的只是本人辛苦,私下多思考,多画图,多了解。 没有最好的形式,也没有最快捷的法子,有的只是本人摸索中一直前行,附上之前刷题笔记: 算法 Notes|LeetCode 349. 两个数组的交加 - easy多想,多画,多练,多思考,多了解,多分享,莫慌,莫怕,一步一足迹前行。 加油~ GitHub 地址如下: https://github.com/HLQ-Strugg...14. 最长公共前缀编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀,返回空字符串 ""。 示例 1: 输出: ["flower","flow","flight"]输入: "fl"示例 2: 输出: ["dog","racecar","car"]输入: ""解释: 输出不存在公共前缀。阐明: 所有输出只蕴含小写字母 a-z 。暴力解法一 入上草图,说思路: 根本校验,输出数组为空间接 return,输出数组只有一个时,同理间接 return;取数组中第一个为基数,顺次判断数组中 char 是否相等,同时更新数组比对后果,也就是基数内容;当基数为空时,间接 return。这里首要明确,最长公共,也就是从数组中的每一个开始比对,如果呈现不一样则进行比对。当初我就是这里犯了嘀咕。 这里附上代码: fun longestCommonPrefix(strs: Array<String>): String { var resultStr = "" if (strs.isEmpty()) { return resultStr } if (strs.size == 1) { return strs[0] } resultStr = strs[0] for(str in strs){ var j = 0 while (j < resultStr.length && j < str.length){ if(str.toCharArray()[j] != resultStr.toCharArray()[j]){ break } j++ } resultStr = resultStr.substring(0,j) if(resultStr.isEmpty()){ break } } return resultStr}耗费状况: ...

November 20, 2020 · 2 min · jiezi

关于kotlin:算法-Notes-|LeetCode-349-两个数组的交集-easy

对于算法而言,生疏而神秘,却是成长经验中必经之路。 已经无数次各种找材料,寻求各种所谓的七天搞定算法秘籍,可后果都是无终而返。 其实换句话来讲,我也是搞 Android 的,有时候看到所谓 7 天让你成为 Android 大牛,也是等闲视之的。没有久远的积攒,哪儿来的大牛?已经折腾很久的货色,现在 easy 一批,说白了,还是工夫久了,写的多了。 一个人,难免会走进各种误区。经验了职场 PUA,顿悟过去,别无他求,自我积攒为上。 还是鸡老大的那句话: Just do it now.送给屏幕前的你我,共勉。 针对算法,将采取暴力 Study 法,勤能补拙!多学多练。 集体是个算法白痴,尽量欠缺每一步,不足之处,欢送吊打~ 欢送各位大佬吊打~ 附上 GitHub 地址: https://github.com/HLQ-Strugg...349. 两个数组的交加给定两个数组,编写一个函数来计算它们的交加。 示例 1: 输出:nums1 = [1,2,2,1], nums2 = [2,2]输入:[2]示例 2: 输出:nums1 = [4,9,5], nums2 = [9,4,9,8,4]输入:[9,4] 阐明: 输入后果中的每个元素肯定是惟一的。咱们能够不思考输入后果的程序。交加概念回顾 以上图为例,A、B 之间重合局部为交加 C。 例如,现有 A、B 如下: A:1 3 4 5 6B:2 3 3 4重合局部的内容为: 3 4可得出交加 C 等于 3 4。 交加的概念,用大白话的形式就是,你有我也有,这是交加。此处衍生并集则是,你的加我的,去掉反复的,就是并集。 ...

November 20, 2020 · 2 min · jiezi

关于kotlin:官方-Kotlin-课程-学习使用-Kotlin-进行-Android-开发的最佳时机

作者 / Android 开发技术推广工程师 Kat Kuan 现在,越来越多的人心愿思考可能反对近程办公的职业,而从事利用开发或者能够实现。对于心愿取得新机遇的人而言,即便过来没有编程教训,也能够立刻开始学习 Android。 咱们于 2016 年公布了 Android 基础知识课程,该课程专为零编程教训的学员打造,并且好评如潮。数万名学员一边构建本人的利用,一边学习着 Android 开发和编程概念。尔后,Android 平台产生重大变动,咱们不仅公布了四个重要的 Android 版本,新增了对 Kotlin 编程语言的反对,还推出了 Jetpack,这一整套库可帮忙开发者用更少的代码更轻松地编写优质利用。有了这些最新更新,是时候为初学者公布下一代培训内容了。 当初,咱们发表推出 Android Kotlin 基础知识 (Android Basics in Kotlin),这是专为想要学习如何构建 Android 利用的零编程教训者打造的全新线上课程。此课程将传授 Kotlin,这种古代编程语言既简洁又高效,备受开发者的青眼。Kotlin 在业内倒退迅速。Indeed Hiring Lab 发现,2018 年至 2019 年这一年期间,Kotlin 语言的职位需要增幅达到 76% (源自 Indeed.com 上美国的科技职位招聘数据)。 自 Google 发表将 Kotlin 作为 Android 开发的首选语言 (Kotlin-first),60% 的业余 Android 开发者曾经采纳了该编程语言。在 Google Play 利用商店排名前 1,000 的利用中,有 70% 的开发语言都采纳了 Kotlin。为了与时俱进并迎接将来倒退,当初正是学习应用 Kotlin 进行 Android 开发的绝佳机会。 课程简介:https://youtu.be/oSim9fBFy-E从头开始学习编程可能让您望而却步,但技术背景并不是学习的必要条件。近期的 Stack Overflow 开发者调查结果 显示,近 40% 的业余开发者并非计算机科学或软件工程业余科班出身。 ...

November 18, 2020 · 1 min · jiezi

关于kotlin:减少崩溃提升体验-使用-Kotlin-打造优质应用

作者 / Florina Muntenescu, Android Developer Advocate 每一个用户都心愿从利用中取得无缝体验。解体会导致差评减少、利用卸载,甚至有损品牌认可度。与社区交换后,咱们理解到开发者采纳 Kotlin 的次要起因之一是为了更平安的代码。我将在本文中讲述 Kotlin 进步开发者代码稳定性的几种形式,也会通过 Google Play 商店统计的后果,看看应用 Kotlin 与解体数量之间是否有相关性 (剧透一下: 当然有!)。 利用品质利用品质不仅影响着用户体验,利用的大量解体还会影响一些其余方面: 利用曝光度  - Google Play 商店举荐由人工策动和算法计算共同完成,其中品质是最大的考量因素之一。品牌  - 产品体现会影响评分和评论,从而影响品牌认可度。更多的 (参加) 用户数量  - 更好的天然搜寻数据和品牌认可度能够带来更好的用户获取和留存,这也会影响参与度和升高漏斗指标。应用 Kotlin 构建的利用呈现解体的可能性升高了 20%。 Kotlin 在其中表演了什么角色?咱们钻研了 Google Play 排名前 1,000 的利用,发现应用 Kotlin 的利用与不应用 Kotlin 的利用相比,其用户解体率低 20%。 比方 Kotlin 的空安全性就让点评的 Android 利用团队拍案叫绝,而且团队开发者还能够通过在 Java 代码中应用 @Nullable 和 @NonNull 等注解来确保 Kotlin 代码取得正确的可空性推断。整体上看,Kotlin 的空平安个性帮忙点评 Android 利用将空指针导致的解体从日均 3 个升高至 0。 ...

November 11, 2020 · 1 min · jiezi

关于kotlin:R8-编译器-为-Kotlin-库和应用-瘦身

作者 / Morten Krogh-Jespeersen, Mads Ager R8 是 Android 默认的程序缩减器,它能够通过移除未应用的代码和优化其余代码的形式升高 Android 利用大小,R8 同时也反对缩减 Android 库大小。除了生成更小的库文件,库压缩操作还能够暗藏开发库里的新个性,等到这些个性绝对稳固或者能够面向公众的时候再对外开放。 Kotlin 对于编写 Android 利用和开发库来说是十分棒的开发语言。不过,应用 Kotlin 反射来缩减 Kotlin 开发库或者利用就没那么简略了。Kotlin 应用 Java 类文件中的元数据 来辨认 Kotlin 语言中的构造。如果程序缩减器没有保护和更新 Kotlin 的元数据,相应的开发库或者利用就无奈失常工作。 R8 当初反对维持和重写 Kotlin 的元数据,从而全面反对应用 Kotlin 反射来压缩 Kotlin 开发库和利用。该个性实用于 Android Gradle 插件版本 4.1.0-beta03。欢送大家踊跃尝试,并在 Issue Tracker 页面 向咱们反馈整体应用感触和遇到的问题。 本文接下来的内容为大家介绍了 Kotlin 元数据的相干信息以及 R8 中对于重写 Kotlin 元数据的反对。 Kotlin 元数据Kotlin 元数据 是存储在 Java 类文件的注解中的一些额定信息,它由 Kotlin JVM 编译器生成。元数据确定了类文件中的类和办法是由哪些 Kotlin 代码形成的。比方,Kotlin 元数据能够通知 Kotlin 编译器类文件中的一个办法实际上是 Kotlin 扩大函数。 ...

November 9, 2020 · 3 min · jiezi

关于kotlin:在-Kotlin-中使用-Dagger-会遇到的陷阱和优化方法

Dagger 在 Android 开发中相当风行,它是一个提供齐全动态和在编译时生成代码的依赖注入框架,它解决了很多基于反射而实现的计划中所遇到的开发和性能问题。 为了让您更好地理解 Dagger 的工作原理,咱们于 2019 年公布了一个 新的教程。本文将重点介绍如何 在 Kotlin 中应用 Dagger ,包含优化构建工夫的 最佳实际 以及一些可能会遇到的问题。 Dagger 是通过 Java 的注解模型实现的,而 Kotlin 中注解的编写形式同 Java 的并不是一一对应的,这篇文章会重点介绍它们之间的不同之处,并且会介绍怎么轻松地将 Dagger 同 Kotlin 联合起来应用。 本文的写作灵感来自 Dagger issue 中的一些倡议,这些倡议间接代表了在 Kotlin 中应用 Dagger 的最佳实际和一些痛点。在此要感激所有的 issue 贡献者。 进步构建效率为了缩短构建工夫,Dagger 在 v2.18 版本中新增了 对 gradle 增量注解解决  (gradle’s incremental annotation processing) 的反对。在 Dagger v2.24 版本中这个性能是默认启用的。如果您应用的是较低版本,您须要增加以下几行代码来激活该性能。 另外,您能够配置 Dagger 让它不要格式化生成的代码。这一选项是在 Dagger v2.18 版本中增加的,并且是 v2.23 版本中的默认行为 (不再生成格式化代码)。如果您应用的是较低的版本,同样能够增加上面的代码来禁用格式化代码以缩短构建工夫。 在 build.gradle 中增加以下编译参数来进步 Dagger 在构建时的性能: allprojects { afterEvaluate { extensions.findByName('kapt')?.arguments { arg("dagger.formatGeneratedSource", "disabled") arg("dagger.gradle.incremental", "enabled") } }}另外,如果您应用的是 Kotlin DSL 脚本文件,那么您须要在 build.gradle.kts 文件中蕴含以下内容: ...

November 1, 2020 · 2 min · jiezi

关于kotlin:kotlin-简要总结

为适应Android的倒退,打算当前的我的项目逐渐采样Kotlin开发,现对kotlin应用做一个小结,内容摘自《第一行代码》及菜鸟教程-Kotlin。 1、变量Kotlin定义一个变量,只容许在变量前申明两种关键字:val和var。val用来申明一个不可变的变量,var用来申明一个可变的变量。 var <标识符> : <类型> = <初始化值> var a: Int = 1val <标识符> : <类型> = <初始化值> val b = 1编译器反对主动类型判断,申明时能够不指定类型。Tips:优先应用val来申明一个变量,当val没法满足需要时再应用var。2、函数语法规定如下 fun methodName(param1: Int, param2: Int): Int { return 0}fun是定义函数的关键字,参数括号那局部用于申明函数会返回什么类型的数据,如不需返回任何数据能够间接不写。当函数中只有一行代码时,不用编写函数题,能够将惟一的一行代码写在函数定义的尾部,两头用等号连贯即可。 fun largeNumber(num1: Int, num2: Int) = max(num1, num2)3、逻辑管制when条件语句when语句容许传入一个任意类型的参数,而后能够在when的构造体定义一系列的条件:匹配值 -> { 执行逻辑 } fun getScore(name: String) = when(name) { "Tom" -> 86 "Jim" -> 77 else -> 0}

September 5, 2020 · 1 min · jiezi

关于kotlin:从Lombok迁移到Kotlin

原文地址: https://dzone.com/articles/mi...更短的代码不是目标,只有更可读的代码才是 作为一个Java开发者,最常见的埋怨是对Java语言简短的埋怨。而其中呈现最多的就是数据类。 数据类,或者元祖,或者record记录类,将来在Java语言可能会隐没,但在那天之前,任何工夫创立一个rest dto, jpa实体,畛域对象,或者任何相似的,Java的冗余就呈现了。在这篇文章里,我会介绍如何从Lombok迁徙到Kotlin,以及从迁徙中能取得的收益。 // 40 Lines of Java code for a class with 2 propertiesimport java.time.LocalDate;import java.util.Objects;public class Person { private String name; private LocalDate dateOfBirth; public Person(String name, LocalDate dateOfBirth) { this.name \= name; this.dateOfBirth \= dateOfBirth; } public String getName() { return name; } public LocalDate getDateOfBirth() { return dateOfBirth; } @Override public boolean equals(Object o) { if (this \== o) return true; if (o \== null || getClass() != o.getClass()) return false; Person person \= (Person) o; return Objects.equals(name, person.name) && Objects.equals(dateOfBirth, person.dateOfBirth); } @Override public int hashCode() { return Objects.hash(name, dateOfBirth); } @Override public String toString() { return "Person{" + "name='" + name + '\\'' + ", dateOfBirth=" + dateOfBirth + '}'; }}要无效的应用数据类,你常常须要一组属性;一个构造函数,一组getter;兴许也会有equals; hashcode和toString办法;另外在一些状况下,还有邪恶的setter到处都是。因为这是个常见问题,一些解决方案呈现了 - Lombok是比拟出名的,但其余还有AutoValue与Immutables。 ...

August 2, 2020 · 2 min · jiezi

关于kotlin:从Lombok迁移到Kotlin

原文地址: https://dzone.com/articles/mi...更短的代码不是目标,只有更可读的代码才是 作为一个Java开发者,最常见的埋怨是对Java语言简短的埋怨。而其中呈现最多的就是数据类。 数据类,或者元祖,或者record记录类,将来在Java语言可能会隐没,但在那天之前,任何工夫创立一个rest dto, jpa实体,畛域对象,或者任何相似的,Java的冗余就呈现了。在这篇文章里,我会介绍如何从Lombok迁徙到Kotlin,以及从迁徙中能取得的收益。 // 40 Lines of Java code for a class with 2 propertiesimport java.time.LocalDate;import java.util.Objects;public class Person { private String name; private LocalDate dateOfBirth; public Person(String name, LocalDate dateOfBirth) { this.name \= name; this.dateOfBirth \= dateOfBirth; } public String getName() { return name; } public LocalDate getDateOfBirth() { return dateOfBirth; } @Override public boolean equals(Object o) { if (this \== o) return true; if (o \== null || getClass() != o.getClass()) return false; Person person \= (Person) o; return Objects.equals(name, person.name) && Objects.equals(dateOfBirth, person.dateOfBirth); } @Override public int hashCode() { return Objects.hash(name, dateOfBirth); } @Override public String toString() { return "Person{" + "name='" + name + '\\'' + ", dateOfBirth=" + dateOfBirth + '}'; }}要无效的应用数据类,你常常须要一组属性;一个构造函数,一组getter;兴许也会有equals; hashcode和toString办法;另外在一些状况下,还有邪恶的setter到处都是。因为这是个常见问题,一些解决方案呈现了 - Lombok是比拟出名的,但其余还有AutoValue与Immutables。 ...

August 2, 2020 · 2 min · jiezi

关于kotlin:从Lombok迁移到Kotlin

原文地址: https://dzone.com/articles/mi...更短的代码不是目标,只有更可读的代码才是 作为一个Java开发者,最常见的埋怨是对Java语言简短的埋怨。而其中呈现最多的就是数据类。 数据类,或者元祖,或者record记录类,将来在Java语言可能会隐没,但在那天之前,任何工夫创立一个rest dto, jpa实体,畛域对象,或者任何相似的,Java的冗余就呈现了。在这篇文章里,我会介绍如何从Lombok迁徙到Kotlin,以及从迁徙中能取得的收益。 // 40 Lines of Java code for a class with 2 propertiesimport java.time.LocalDate;import java.util.Objects;public class Person { private String name; private LocalDate dateOfBirth; public Person(String name, LocalDate dateOfBirth) { this.name \= name; this.dateOfBirth \= dateOfBirth; } public String getName() { return name; } public LocalDate getDateOfBirth() { return dateOfBirth; } @Override public boolean equals(Object o) { if (this \== o) return true; if (o \== null || getClass() != o.getClass()) return false; Person person \= (Person) o; return Objects.equals(name, person.name) && Objects.equals(dateOfBirth, person.dateOfBirth); } @Override public int hashCode() { return Objects.hash(name, dateOfBirth); } @Override public String toString() { return "Person{" + "name='" + name + '\\'' + ", dateOfBirth=" + dateOfBirth + '}'; }}要无效的应用数据类,你常常须要一组属性;一个构造函数,一组getter;兴许也会有equals; hashcode和toString办法;另外在一些状况下,还有邪恶的setter到处都是。因为这是个常见问题,一些解决方案呈现了 - Lombok是比拟出名的,但其余还有AutoValue与Immutables。 ...

August 2, 2020 · 2 min · jiezi

关于kotlin:kotlin中的使用小技巧总结

1.kotlin中lateinit和by lazy的区别lazy { ... }只能被用在被val润饰的变量上,而lateinit只能被用var润饰的变量上,因为被lateinit润饰的字段无奈被编译为一个final字段、因而无奈保障它的不可变性。被lateinit润饰的变量有一个幕后字段用来存储它的值,而by lazy { ... }创立了一个蕴含by lazy { ... }中代码返回值的实例对象,实例对象持有这个值并生成一个能够在实例对象中调用的这个值的getter。所以如果你须要在代码中应用幕后字段的话,应用lateinit被lateinit润饰的变量能够在对象(代码)的任何中央进行初始化,而且同一个类的不同对象能够对这个变量进行屡次的初始化(赋值)。然而,对于by lazy { ... }润饰的变量,只领有惟一一个申明在{}中的初始化结构器,如果你想要批改它,你只能通过在子类中覆写的形式来批改它的值。所以,如果你想要你的属性在其余中央以不是你当时定义好的值初始化的话,应用lateinit by lazy { ... }的初始化默认是线程平安的,并且能保障by lazy { ... }代码块中的代码最多被调用一次。而lateinit var默认是不保障线程平安的,它的状况齐全取决于使用者的代码。Lazy实例是有值的,这个值能够被存储、传递和应用。然而,被lateinit var润饰的变量不存储任何多余的运行时状态,只有值还未被初始化的null值。如果你持有一个Lazy实例的援用,你能够应用它的isInitialized()办法来判断它是否曾经被初始化。从Kotlin1.2开始,你也能够应用办法援用的形式来获取这个值。by lazy { ... }中传递的lambda表达式可能会捕捉它的闭包中应用的上下文的援用,援用会始终被持有直到变量被初始化。因而这样可能会导致内存透露,所以认真思考你在lambda表达式中应用的值是否正当。原文链接:https://stackoverflow.com/que... Here are the significant differences between lateinit var and by lazy { ... } delegated property:lazy { ... } delegate can only be used for val properties, whereas lateinit can only be applied to vars, because it can't be compiled to a final field, thus no immutability can be guaranteed;lateinit var has a backing field which stores the value, and by lazy { ... } creates a delegate object in which the value is stored once calculated, stores the reference to the delegate instance in the class object and generates the getter for the property that works with the delegate instance. So if you need the backing field present in the class, use lateinit;In addition to vals, lateinit cannot be used for non-nullable properties and Java primitive types (this is because of null used for uninitialized value);lateinit var can be initialized from anywhere the object is seen from, e.g. from inside a framework code, and multiple initialization scenarios are possible for different objects of a single class. by lazy { ... }, in turn, defines the only initializer for the property, which can be altered only by overriding the property in a subclass. If you want your property to be initialized from outside in a way probably unknown beforehand, use lateinit.Initialization by lazy { ... } is thread-safe by default and guarantees that the initializer is invoked at most once (but this can be altered by using another lazy overload). In the case of lateinit var, it's up to the user's code to initialize the property correctly in multi-threaded environments.A Lazy instance can be saved, passed around and even used for multiple properties. On contrary, lateinit vars do not store any additional runtime state (only null in the field for uninitialized value).If you hold a reference to an instance of Lazy, isInitialized() allows you to check whether it has already been initialized (and you can obtain such instance with reflection from a delegated property). To check whether a lateinit property has been initialized, you can use property::isInitialized since Kotlin 1.2.A lambda passed to by lazy { ... } may capture references from the context where it is used into its closure.. It will then store the references and release them only once the property has been initialized. This may lead to object hierarchies, such as Android activities, not being released for too long (or ever, if the property remains accessible and is never accessed), so you should be careful about what you use inside the initializer lambda.Also, there's another way not mentioned in the question: Delegates.notNull(), which is suitable for deferred initialization of non-null properties, including those of Java primitive types.在我的项目中的理论使用示例: ...

July 24, 2020 · 5 min · jiezi

关于kotlin:除了Android开发Kotlin-还能做什么六款优质Kotlin项目分享

Kotlin 语言 2011 年由 JetBrains 推出,2012 年开源,2017 年成为 Android 官网开发语言,并于 2019 年成为 Andoid 开发官网首选语言。凭借其原生反对 Java 以及更少代码量的劣势,也有越来越多的开发者投向 Kotlin 的怀抱,同时 Kotlin 在其余畛域的利用也越来越宽泛,明天就为大家介绍六款优质的 Kotlin 我的项目。 1.AndroidZdog我的项目作者:prostory 开源许可协定:MIT 我的项目地址:https://gitee.com/prostory/AndroidZdog Android平台上的伪3D图形动画引擎Zdog,应用kotlin编写。 2.HiWeather我的项目作者:ZhiyuanLing 开源许可协定:GPL-3.0 我的项目地址:https://gitee.com/vitoling/HiWeather 一个应用 Kotlin 语言开发的天气网站,其余应用的技术包含 SpringBoot、Webmagic等。 3.wechat-miniprogram-plugin我的项目作者:zxy 开源许可协定:MulanPSL-1.0 我的项目地址:https://gitee.com/zxy_c/wechat-miniprogram-plugin 基于JetBrains平台的微信小程序插件。 4.bk-ci我的项目作者:腾讯蓝鲸智云 开源许可协定:MIT 我的项目地址:https://gitee.com/Tencent-BlueKing/bk-ci bk-ci是一个收费并开源的CI服务,可助你自动化构建-测试-公布工作流,继续、疾速、高质量地交付你的产品。 5.Twobbble我的项目作者:生存以上生存以下 开源许可协定:Apache-2.0 我的项目地址:https://gitee.com/550609334/Twobbble 这是一个齐全应用Kotlin开发,小而美的Dribbble客户端。 6.OKBook我的项目作者:Xiaolei123 开源许可协定:Apache-2.0 我的项目地址:https://gitee.com/xcode_xiao/OKBook kotlin + 协程 + MVVM 模式来编写的看小说APP。 以上六款开源我的项目不晓得是否让大家更理解 Kotlin,如果你还想在 Gitee 上看到更多 Kotlin 我的项目,那么就点击前面的链接去看看吧:https://gitee.com/explore/all?lang=Kotlin&order=starred

July 23, 2020 · 1 min · jiezi

关于kotlin:kotlin基础

记录一下与java相比的一些根底重要的点 1.基础知识 1.1 根本类型 kotlin中没有java根本类型的int、float、double等,所有货色都是对象,这与java相似。然而kotlin对数字没有隐式拓宽转换,须要显示转换;数字字面量不反对八进制。 1.2 包与导入 应用import关键字,性能上与java差不多。import不限于导入类,还能够导入申明如枚举常量。不同的是 没有相似import static的性能。 1.3 控制流 应用if、when、for、while when取代了switch性能,然而比switch弱小,能够多条件一起,逗号分隔 when (x) { 0, 1 -> print("x == 0 or x == 1") else -> print("otherwise")}能够应用任意表达式,而不只是常量;能够检测一个值是否在一个区间 when (x) { in 1..10 -> print("x is in the range") in validNumbers -> print("x is valid") !in 10..20 -> print("x is outside the range") else -> print("none of the above")}for/while的应用跟java有点相似,for循环能够对迭代器对象进行遍历,与in应用。 1.4 返回和跳转 return、continue、break 与java的性能一样,加了标签性能。kotlin的表达式都能够用标签(Label)来标记。标签=标识符+@,性能是记录地址,来跳转到相应地位。 1.5 类与对象 ...

July 20, 2020 · 3 min · jiezi

KotlinVueSpring-Data-JPAMySQL-增查改删

概述:Kotlin为后端开发语言,长久层是Spring Data JPA前后端拆散,进行简略增查改删(CRUD)前端应用VUE数据库应用MySQL Vue前端代码,不再反复。以下是Kotlin后盾代码 EmployeeController.ktpackage com.example.kotlinjpacrud.controllerimport com.example.kotlinjpacrud.entity.Employeeimport com.example.kotlinjpacrud.repositories.EmployeeRepositoryimport org.springframework.data.domain.Pageimport org.springframework.data.domain.Pageableimport org.springframework.data.domain.Sortimport org.springframework.data.web.PageableDefaultimport org.springframework.http.HttpStatusimport org.springframework.http.ResponseEntityimport org.springframework.web.bind.annotation.*import javax.validation.Valid@RestController@RequestMapping("/api/employee")class EmployeeController(private val employeeRepository: EmployeeRepository) { /** * 获取所有员工分页 * 以字段Id为降序 * 没有为3条记录 */ @GetMapping fun getAllEmployees(@PageableDefault(sort = ["id"], direction = Sort.Direction.DESC, size = 3) pageable: Pageable): Page<Employee> { return employeeRepository.findAll(pageable) } /** * 新增员工 */ @PostMapping fun createEmployee(@Valid @RequestBody employee: Employee): Employee { return employeeRepository.save(employee) } /** * 依据ID获取员工 */ @GetMapping("/{id}") fun getEmployeeById(@PathVariable(value = "id") employeeId: Long): ResponseEntity<Employee> { return employeeRepository.findById(employeeId) .map { employee -> ResponseEntity.ok(employee) } .orElse(ResponseEntity.notFound().build()) } /** * 批改员工 */ @PutMapping fun updateEmployeeById(@Valid @RequestBody newEmployee: Employee): ResponseEntity<Employee> { return employeeRepository.findById(newEmployee.id) .map { existingArticle -> val updatedArticle: Employee = existingArticle .copy(name = newEmployee.name, gender = newEmployee.gender, age = newEmployee.age, introduce = newEmployee.introduce) ResponseEntity.ok().body(employeeRepository.save(updatedArticle)) }.orElse(ResponseEntity.notFound().build()) } /** * 依据ID删除 */ @DeleteMapping("/{id}") fun deleteEmployeeById(@PathVariable(value = "id") employeeId: Long): ResponseEntity<Void> { return employeeRepository.findById(employeeId) .map { deleteEmployee -> employeeRepository.delete(deleteEmployee) ResponseEntity<Void>(HttpStatus.OK) }.orElse(ResponseEntity.notFound().build()) }}Employee.ktpackage com.example.kotlinjpacrud.entityimport com.example.kotlinjpacrud.enums.Genderimport javax.persistence.Entityimport javax.persistence.GeneratedValueimport javax.persistence.Id@Entitydata class Employee( @Id @GeneratedValue var id: Long =0, var name: String ="", var gender: Gender = Gender.MALE, var age: Int =0, var introduce: String ="")EmployeeRepository.tkpackage com.example.kotlinjpacrud.repositoriesimport com.example.kotlinjpacrud.entity.Employeeimport org.springframework.data.jpa.repository.JpaRepositoryimport org.springframework.stereotype.Repository@Repositoryinterface EmployeeRepository :JpaRepository<Employee,Long> {}

July 10, 2020 · 1 min · jiezi

Kotlin-Hello-World

1 KotlinKotlin是一种在JVM上运行的静态类型编程语言,被称为Android界的Wsift,由JetBrains设计。Kotline可以编译成Java字节码,也可以编译成JavaScript,方便在没有JVM的设备上运行。Google宣布在Google I/O 2017上宣布Kotlin成为Android官方语言。 笔者不是专攻Android的,是做服务端的,尽管目前大部分都是使用Java做后端,但是也有一些Kotlin做后端的资料,比如Kotlin结合Spring Boot的也有不少文章,因此笔者决定使用Kotlin进行后端开发。 那么,先从Hello world开始。 2 新建工程IDE用的是IDEA,新建工程并选择Kotlin:项目名:结构应该长这样(居然连个Main都没有。。。): 3 Main在src下新建一个Main.kt:代码在图中就不再贴一次了。当然可能有人会问Stirng [] args去哪里了,那就把它加上:IDEA提示从Kotlin1.3开始main参数不是必要的,因此把它去掉了。不过老实说Kotlin比起Java还真的简洁。 4 添加运行配置选择Add Configuration,接着选择Kotlin:在Main class:处输入默认包MainKt: 5 运行Shift+F10或者点击绿色小箭头运行即可。

June 26, 2020 · 1 min · jiezi

Kotlin学习笔记

1 概述这篇文章首先会介绍Kotlin的特点,接着介绍Kotlin与Java的语法比较。 2 Kotlin特点一门现代化的编程语言可开发跨平台应用,web,Socket,安卓,js,NativeApp等静态编程语言,性能基本与原声Java相当100%兼容Java(说是兼容但实际上有些坑,可以戳这里看看)简洁:跟Java相比真的是简洁很多,语法糖特别舒服安全:彻底解决写Java基本上都会遇到的著名的NullPointerException问题,结合编译器可以在编译截断发现几乎所有可能存在NPE问题的代码互操作性:基于JVM,可以直接拿现有的Java库用工具友好:和JetBrains的IDE结合简直舒服得不要不要的支持函数式编程:比如Lambda表达式支持协程:协程像是非常轻量级的县城,协程将复杂性放入库来简化异步编程,逻辑可以在协程中顺序表达,底层库负责解决异步性,很重要的一点是协程挂起不会阻塞其他线程。官方一个demo是开启10w个协程: 支持扩展函数:类似C#,能够扩展一个类的新功能而无需继承类或者使用装饰者这样的设计模式,Kotlin支持扩展函数和扩展属性泛型:当然Java也支持泛型,但是Kotlin比Java支持得更好不依赖XML下面进入Kotlin的语法部分。 3 基本语法无;结尾println()代替System.out.println();输出语句中使用$变量名代替Java中的+变量名,比如println("age:$age")而不是System.out.println("age:"+age)三引号(三个双引号连在一起)中的字符串不会进行转义4 变量与常量var声明变量val声明常量可以在var/val后面加上类型,比如val a:Int如上图提示val不能被赋值,提示改为var。val类似与Java中的final,虽然val引用自身不可变,但是指向的对象是可以改变的。 val只能进行唯一一次初始化,如果编译器能确保只有唯一一条初始化语句被执行,可以根据条件进行不同的初始化操作: val a:Intif (4>3){ a = 9}else{ a = 10}5 表达式和语句Java中所有的控制结构都是语句,在Kotlin中除了三大循环(while,for,do while)外,大多数控制结构都是表达式。比如if是表达式而不是语句。也就是说,if有值而不像Java里面一样没有值(语句)。例子: var a = if (3>2) 3 else 2fun main(){ var a = max(4,9)}fun max(a:Int,b:Int): Int = if(a>b) a else b6 枚举使用enum class而不是Java中的enum: fun main(){ val months = Months.May println(months.days)}enum class Months(val days:Int){ May(31), Jun(30)}7 whenwhen相当于Java中的switch: fun main(){ val months = Months.May when(months) { Months.May -> print("May") Months.Jun -> print("June") }}enum class Months(val days:Int){ May(31), Jun(30),;}使用->进行了简化。 ...

June 26, 2020 · 2 min · jiezi