Kotlin(kotlin文件夹的作用)

Kotlin}
// 为传递这个点击事件,专门定义了一个接口 public interface OnClickListener { void onClick(View v); }
// 监听鼠标点击事件 public vo

}

//专门定义了一个接口来传递这个点击事件

公共接口OnClickListener {

无效onClick(查看v);

}

//监听鼠标点击事件

公共无效setOnContextClickListener(OnContextClickListener l){

getListenerInfo().mOnContextClickListener=l;

}

//专门定义了一个接口来传递这个鼠标点击事件

公共接口OnContextClickListener {

Boolean onContextClick(View v);

}

要在Android 上设置单击和鼠标单击事件,请编写:

//设置手指点击事件

image.setOnClickListener(new View.OnClickListener() {

@覆盖

公共无效onClick(查看v){

转到预览();

}

});

//设置鼠标点击事件

image.setOnContextClickListener(new View.OnContextClickListener() {

@覆盖

公共无效onContextClick(查看v){

转到预览();

}

});

您是否认为这段代码太冗长?

现在,假设我们是语言设计者,让我们首先看看上面代码中的问题。

定义者:每次增加一个方法,我们都要增加一个新的接口:OnClickListener、OnContextClickListener 调用者:我们要写很多匿名内部类,冗余、笨重、不集中。

如果你仔细看上面的代码,你会发现开发人员实际上只关心一行代码。

转到预览();

这是提取核心逻辑的最简单方法。

image.setOnClickListener { gotoPreview() }

image.setOnContextClickListener { gotoPreview() }

Kotlin 语言的设计者做了什么?

将接口定义替换为函数类型,并使用lambda 表达式作为函数参数

上面View.java 的Kotlin 等效项是:

//查看.kt

var mOnClickListener: ((视图) – 单位)=null

var mOnContextClickListener:((视图)-单位)?

fun setOnClickListener(l: (视图) – 单位) {

mOnClickListener=l;

}

有趣的setOnContextClickListener(l: (视图) – 单位) {

mOnContextClickListener=l;

}

上述方法具有以下优点:

Definer:减少两个接口类的定义。 来电者:代码更简洁了。

细心的朋友可能已经发现了问题所在。 Android 不提供View.java 的Kotlin 实现。为什么在我们的演示中使用Lambda 来简化事件监控?

//实际开发中经常使用这种简化的方法

setOnClickListener { gotoPreview() }

原因如下: OnClickListener满足SAM转换的要求,允许编译器自动运行转换层并使用lambda表达式简化函数调用。

那么SAM到底是什么?

2-2 SAM 转换(Single Abstract Method Conversions)

SAM(Single Abstract Method),顾名思义,是只有一个抽象方法的类或接口,但在Kotlin和Java8中,SAM代表只有一个抽象方法的接口。对于满足SAM要求的接口,编译器可以进行SAM转换。这允许您使用lambda 表达式来省略接口类中的参数。

注意:Java8 的SAM 有一个独特的名称:FunctionalInterface。

功能接口的限制是:所有这些都是必需的。

它必须是一个接口,而不是一个抽象类。一个接口只有一个抽象方法。默认情况下,可以实现多种方法。

因此,对于View.java,即使这是Java 代码,Kotlin 编译器也知道其参数OnClickListener 符合SAM 转换的条件,因此它会自动执行以下转换:

转换前:

公共无效setOnClickListener(OnClickListener l)

转换后:

fun setOnClickListener(l: (视图) – 单位)

//实际上这是:

fun setOnClickListener(l: ((View!) – 单位)?)

((View!) – Unit)? 表示该参数可能为空。

2-3 Lambda 表达式引发的8种写法

当lambda表达式用作函数参数时,有时可以省略,使代码看起来更简洁。然而,大多数初学者会觉得很困惑,因为相同的代码可以用8 种不同的方式编写。

理解lambda 表达式的省略逻辑实际上非常简单。这意味着要写更多。

大家好,请按照下面的流程,跟我一起写吧。

2-3-1 第1种写法

这是原始代码,基本上使用object 关键字定义一个匿名内部类。

image.setOnClickListener(object: View.OnClickListener {

覆盖fun onClick(v: View?) {

转到预览(v)

}

})

2-3-2 第2种写法

由于删除object 关键字会生成Lambda 表达式,因此您还必须删除其中的覆盖方法。

image.setOnClickListener(View.OnClickListener { view: 视图?-

转到预览(显示)

})

上面的View.OnClickListener是这样调用的: SAM Constructor—— SAM 构造函数由编译器生成。 Kotlin 允许您以这种方式定义lambda 表达式。

思考题:

目前,View.OnClickListener {}在语义上是一个Lambda表达式,但在语法上它仍然是一个匿名内部类。这是对的?

2-3-3 第3种写法

Kotlin 中的Lambda 表达式不需要SAM 构造函数,因此您也可以将其删除。

image.setOnClickListener({ view: 显示? –

转到预览(显示)

})

2-3-4 第4种写法

Kotlin 支持类型推断,因此您可以删除View?

image.setOnClickListener({ 查看-

转到预览(显示)

})

2-3-5 第5种写法

如果您的Kotlin lambda 表达式只有一个参数,您可以按原样编写。

image.setOnClickListener({ 它-

转到预览(它)

})

2-3-6 第6种写法

对于Kotlin Lambda 可以省略。

image.setOnClickListener({

转到预览(它)

})

2-3-7 第7种写法

如果使用Kotlin Lambda 作为函数的最后一个参数,则可以将Lambda 移至外部。

image.setOnClickListener() {

转到预览(它)

}

2-3-8 第8种写法

如果Kotlin 只有一个Lambda 作为函数参数,则() 可以省略。

image.setOnClickListener {

转到预览(它)

}

一旦你遵循这个过程并在IDE 中编写几次,它就会成为你的第二天性。你必须写它,即使你读了这篇文章你也不会记住它。

2-4 函数类型,高阶函数,Lambda表达式三者之间的关系

抽象函数参数的类型及其返回值就可以得出函数的类型。 (View) – Unit 表示参数类型为View,返回类型为Unit。如果函数的参数或返回类型是函数类型,则该函数是高阶函数。显然,我们刚刚创建了一个高阶函数,但它相对简单。 Lambda 是函数的缩写

理解图:函数类型、高阶函数和lambda 表达式之间的关系:

我们回过头来看看官方文档中提供的示例。

有趣的T,R集合.fold(

初始: R,

组合:(acc: R,nextElement: T)-R

):R{

var Accumulator: R=初始值

for(其中的元素: T){

累加器=join(累加器, 元素)

}

返回累加器

}

看一下这个函数类型:(acc: R, nextElement: T) – R,你能快速理解这个函数有两个参数吗?第一个参数的类型为R,第二个参数的类型为T,函数的返回类型为R。

3. 带接收者(Receiver)的函数类型:A.(B,C) – D

说实话,这个名字对于初学者来说不太友好:Function Types With Receiver 里面的所有单词(单词)我们都认识,但是这么多的信息对于初学者来说确实很难理解它的本质是什么。

仍然有一个不可避免的问题:“为什么?”

3-1 为什么要引入:带接收者的函数类型?

在上一章中,我写了使用apply 来简化逻辑:

修复前:

如果(用户!=空){

……

用户名.文本=用户名

网站.文本=用户.博客

image.setOnClickListener { gotoImagePreviewActivity(用户) }

}

更改后:

用户?应用{

……

用户名.文本=姓名

网站.文本=博客

image.setOnClickListener { gotoImagePreviewActivity(this) }

}

请问大家一个问题:这个apply方法应该如何实现呢?

上面的语句实际上是一个简化的Lambda表达式。让我们反转一下,看看简化前是什么样子。

//apply 必须是一个函数,因此() 存在但被省略

用户?apply() {

……

}

//Lambda 必须在() 内

用户?apply({ … })

//gotoImagePreviewActivity(this)中的this代表用户

//所以user必须是apply函数的参数,参数名称为:

用户?apply({ this: 用户- … })

那么问题就变得很清楚了,apply实际上接收到了一个Lambda表达式:{ this: User – . }。让我们来实现这个apply方法。

fun User.apply(block: (self: User) – 单位): User{

块(自身)

返回这个

}

用户?apply { self: 用户-

……

用户名.文本=self.名字

网站.文本=self.博客

image.setOnClickListener { gotoImagePreviewActivity(this) }

}

Kotlin 的函数参数不能命名为this ,因此我们在这里使用的self 和我们创建的apply 仍然必须通过self.name 访问成员变量,但是Kotlin 语言设计器可以为您做到这一点。

//改成这个

//

fun User.apply(block: (this: User) – 单位): User{

//这里需要传递参数

//

块(这个)

返回这个

}

用户?apply { this: 用户-

……

//选修的

//

用户名.文本=this.name

网站.文本=博客

image.setOnClickListener { gotoImagePreviewActivity(this) }

}

从上面的例子可以看出,我们推导的apply实现比较麻烦,需要我们自己调用block(this)。这就是为什么Kotlin 引入了带有接收器的函数类型,以简化apply 的定义。

//带接收者的函数类型

//

fun User.apply(block: User.() – Unit): User{

//不需要再次传递这个

//

堵塞()

返回这个

}

用户?apply { this: 用户-

……

用户名.文本=this.name

网站.文本=this.博客

image.setOnClickListener { gotoImagePreviewActivity(this) }

}

现在,关键就在这里。上面的apply方法看起来是不是给User添加了一个成员方法apply()?

类用户(){

值名称: 字符串=\”\”

val blog: 字符串=\”\”

有趣的应用(){

//成员方法可以通过this访问成员变量

用户名.文本=this.name

网站.文本=this.博客

image.setOnClickListener { gotoImagePreviewActivity(this) }

}

}

因此,具有接收者的函数类型在外部等同于成员方法。然而,本质上这是通过编译器注入来完成的。

图片摘要:

思考题2:

带有接收者的函数类型也可以代表扩展函数吗?

思考题3:

请问一个问题:A、(B,C)-D 代表什么函数?

4. HTML Kotlin DSL 实战

官方文档的高阶函数章节描述了使用高阶函数来实现类型安全的HTML 构建器。官方文档中的例子比较复杂,所以我们写一个简化版本来练习。

4-1 效果展示:

val html 内容=html {

头{

title { “Kotlin Jetpack 的工作原理” }

}

身体{

h1 {“Kotlin Jetpack 的工作原理”}

p { “———————————————————— ——– ——\” }

p { \”一个非常简单的项目,向您展示如何逐步使用Kotlin 和Jetpack\” }

p { “———————————————————— ——– ——\” }

p {“我让这个项目尽可能简单。”

\’让您专注于如何使用Kotlin 和Jetpack\’ +

而不是理解业务逻辑。

p { \”从\”Java + MVC\”重写为\”\” +

\’“Kotlin + 协程+ Jetpack + Clean MVVM”,\’ +

\’ 逐行提交,逐次提交。 \’}

p { “———————————————————— ——– ——\” }

p {“屏幕截图:”}

img(src=“https://user-gold-cdn.xitu.io/2020/6/15/172b55ce7bf25419?imageslim”,

alt=“Kotlin Jetpack 的工作原理”)

}

}.toString()

println(html内容)

上述代码的输出将如下所示:

Kotlin Jetpack 的工作原理

Kotlin Jetpack In Action

————————————–

一个非常简单的项目,向您展示如何逐步使用Kotlin 和Jetpack。

————————————–

我让这个项目尽可能简单,这样我就可以专注于如何使用Kotlin 和Jetpack,而不是理解业务逻辑。

将其从“Java + MVC”重写为“Kotlin + Coroutines + Jetpack + Clean MVVM”,逐行,逐次提交。

————————————–

截图:

4-2 HTML Kotlin DSL 实现

4-2-1 定义节点元素的接口

界面元素{

//每个节点必须实现render方法

有趣的渲染(builder: StringBuilder,indent: String): String

}

所有HTML 节点必须实现Element 接口,并在渲染方法中实现HTML 代码的拼接: title Kotlin Jetpack In Action /title

4-2-2 定义基础类

/**

每个节点都有一个名称。 content: Kotlin Jetpack 的工作原理

*/

打开类BaseElement(val name: String, val content: String=\”\”) : Element {

//每个节点有很多子节点

val 子级=ArrayList()

//存储节点参数:src、alt里面

val hashMap=HashMapString, String()

/**

HTML: Kotlin Jetpack 拼接行为

*/

覆盖乐趣渲染(builder: StringBuilder,indent: String): String {

生成器.追加(“

n

d

e

n

t

缩进

缩进名称\\n”)

if (content.isNotBlank()) {

生成器.append(\’

n

d

e

n

t

缩进

缩进内容\\n\’)

}

儿童.forEach {

it.render(builder, \”KaTeX 解析错误: 需要\’EOF\’ 但在位置12: 缩进\’) } builder.append.indent/$name\\n\”)

返回builder.toString()

}

}

4-2-3 定义各个子节点:

//这是HTML : 中最外面的标签

HTML 类: BaseElement(\”html\”) {

有趣的头(Block: Head.() – Unit): Head {

val 头=头()

head.block()

之后

ldren += head
return head
}

fun body(block: Body.() -> Unit): Body {
val body = Body()
body.block()
this.children += body
return body
}
}

// 接着是 标签
class Head : BaseElement(“head”) {
fun title(block: () -> String): Title {
val content = block()
val title = Title(content)
this.children += title
return title
}
}

// 这是 Head 里面的 title 标签 <br/>
class Title(content: String) : BaseElement(“title”, content)

// 然后是 标签
class Body : BaseElement(“body”) {
fun h1(block: () -> String): H1 {
val content = block()
val h1 = H1(content)
this.children += h1
return h1
}

fun p(block: () -> String): P {
val content = block()
val p = P(content)
this.children += p
return p
}

fun img(src: String, alt: String): IMG {
val img = IMG().apply {
this.src = src
this.alt = alt
}

this.children += img
return img
}
}

// 剩下的都是 body 里面的标签
class P(content: String) : BaseElement(“p”, content)
class H1(content: String) : BaseElement(“h1”, content)

class IMG : BaseElement(“img”) {
var src: String
get() = hashMap[“src”]!!
set(value) {
hashMap[“src”] = value
}

var alt: String

最后

小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

资料⬅专栏获取
img
}
}

// 剩下的都是 body 里面的标签
class P(content: String) : BaseElement(“p”, content)
class H1(content: String) : BaseElement(“h1”, content)

class IMG : BaseElement(“img”) {
var src: String
get() = hashMap[“src”]!!
set(value) {
hashMap[“src”] = value
}

var alt: String

最后

小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。

[外链图片转存中…(img-yvcoM7Q3-1719091195081)]一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

资料⬅专栏获取

#以上关于Kotlin的相关内容来源网络仅供参考,相关信息请以官方公告为准!

原创文章,作者:CSDN,如若转载,请注明出处:https://www.sudun.com/ask/91808.html

(0)
CSDN的头像CSDN
上一篇 2024年6月23日
下一篇 2024年6月23日

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注