| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 移动开发 -> Kotlin-编程核心基石—高阶函数,Android开发面试解答之Handler -> 正文阅读 |
|
[移动开发]Kotlin-编程核心基石—高阶函数,Android开发面试解答之Handler |
2. 为什么要引入 Lambda 和 高阶函数?刚接触到高阶函数和 Lambda 的时候,我就一直有个疑问:为什么要引入 Lambda 和 高阶函数?这个问题,官方文档里没有解答,因此我只能自己去寻找。 2-1 Lambda 和 高阶函数解决了什么问题?这个问题站在语言的设计者角度会更明了,让我们看个实际的例子,这是 Android 中的 View 定义,我省略了大部分代码: // View.java // 监听手指点击事件 // 为传递这个点击事件,专门定义了一个接口 // 监听鼠标点击事件
etListenerInfo().mOnContextClickListener = l; // 为传递这个鼠标点击事件,专门定义了一个接口 Android 中设置点击事件和鼠标点击事件,分别是这样写的: // 设置手指点击事件 // 设置鼠标点击事件 请问各位小伙伴有没有觉得这样的代码很啰嗦? 现在我们假装自己是语言设计者,让我们先看看上面的代码存在哪些问题:
仔细看上面的代码,开发者关心的其实只有一行代码: gotoPreview(); 如果将其中的核心逻辑抽出来,这样子才是最简明的: image.setOnClickListener { gotoPreview() } Kotlin 语言的设计者是怎么做的?是这样:
与上面 View.java 的等价 Kotlin 代码如下: //View.kt fun setOnClickListener(l: (View) -> Unit) { fun setOnContextClickListener(l: (View) -> Unit) { 以上做法有以下的好处:
细心的小伙伴可能已经发现了一个问题:Android 并没有提供 View.java 的 Kotlin 实现,为什么我们 Demo 里面可以用 Lambda 来简化事件监听? // 在实际开发中,我们经常使用这种简化方式 原因是这样的:由于 那么, 2-2 SAM 转换(Single Abstract Method Conversions)
注:Java8 中的 SAM 有明确的名称叫做: FunctionalInterface 的限制如下,缺一不可:
也就是说,对于 View.java 来说,它虽然是 Java 代码,但 Kotlin 编译器知道它的参数 转换前: public void setOnClickListener(OnClickListener l)
fun setOnClickListener(l: (View) -> Unit)
2-3 Lambda 表达式引发的8种写法当 Lambda 表达式作为函数参数的时候,有些情形下是可以简写的,这时候可以让我们的代码看起来更简洁。然而,大部分初学者对此也比较头疼,同样的代码,能有 8 种不同的写法,确实也挺懵的。 要理解 Lambda 表达式的简写逻辑,其实很简单,那就是: 各位小伙伴可以跟着我接下来的流程来一起写一写: 2-3-1 第1种写法这是原始代码,它的本质是用 object 关键字定义了一个 image.setOnClickListener(object: View.OnClickListener { 2-3-2 第2种写法如果我们删掉 image.setOnClickListener(View.OnClickListener { view: View? -> 上面的 思考题:这时候, 2-3-3 第3种写法由于 Kotlin 的 Lambda 表达式是不需要 image.setOnClickListener({ view: View? -> 2-3-4 第4种写法由于 Kotlin 支持 image.setOnClickListener({ view -> 2-3-5 第5种写法当 Kotlin Lambda 表达式只有一个参数的时候,它可以被写成 image.setOnClickListener({ it -> 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表达式三者之间的关系
一张图看懂: 回过头再看官方文档提供的例子: fun <T, R> Collection.fold( 看看这个函数类型: 3. 带接收者(Receiver)的函数类型:A.(B,C) -> D说实话,这个名字也对初学者不太友好: 还是绕不开一个问题:为什么? 3-1 为什么要引入:带接收者的函数类型?我们在上一章节中提到过,用 apply 来简化逻辑,我们是这样写的: 修改前: if (user != null) {
user?.apply { 请问:这个 apply 方法应该怎么实现? 上面的写法其实是简化后的 Lambda 表达式,让我们来反推,看看它简化前是什么样的: // apply 肯定是个函数,所以有 (),只是被省略了 // Lambda 肯定是在 () 里面 // 由于 gotoImagePreviewActivity(this) 里的 this 代表了 user 所以,现在问题非常明确了,apply 其实接收一个 Lambda 表达式: fun User.apply(block: (self: User) -> Unit): User{ user?.apply { self: User -> 由于 Kotlin 里面的函数形参是不允许被命名为 // 改为 this user?.apply { this: User -> 从上面的例子能看到,我们反推的 apply 实现比较繁琐,需要我们自己调用: // 带接收者的函数类型 user?.apply { this: User -> 现在,关键来了。上面的 apply 方法是不是看起来就像是在 User 里增加了一个成员方法 apply()? class User() { fun apply() { 所以,从外表上看,带接收者的函数类型,就等价于成员方法。但从本质上讲,它仍是通过编译器注入 this 来实现的。 一张图总结: 思考题2:带接收者的函数类型,是否也能代表扩展函数? 思考题3:请问: 4. HTML Kotlin DSL 实战官方文档在高阶函数的章节里提到了:用高阶函数来实现 类型安全的 HTML 构建器。官方文档的例子比较复杂,让我们来写一个简化版的练练手吧。 4-1 效果展示:val htmlContent = html { println(htmlContent) 以上代码输出的内容是这样的: Kotlin Jetpack In Action----------------------------------------- A super-simple project demonstrating how to use Kotlin and Jetpack step by step. ----------------------------------------- I made this project as simple as possible, so that we can focus on how to use Kotlin and Jetpack rather than understanding business logic. We will rewrite it from "Java + MVC" to "Kotlin + Coroutines + Jetpack + Clean MVVM", line by line, commit by commit. ----------------------------------------- ScreenShot: 4-2 HTML Kotlin DSL 实现4-2-1 定义节点元素的接口interface Element { 所有的 HTML 节点都要实现 Element 接口,并且在 render 方法里实现 HTML 代码的拼接: 4-2-2 定义基础类/**
/**
4-2-3 定义各个子节点:// 这是 HTML 最外层的标签: fun body(block: Body.() -> Unit): Body { 4-2-3 定义各个子节点:// 这是 HTML 最外层的标签: fun body(block: Body.() -> Unit): Body { |
|
移动开发 最新文章 |
Vue3装载axios和element-ui |
android adb cmd |
【xcode】Xcode常用快捷键与技巧 |
Android开发中的线程池使用 |
Java 和 Android 的 Base64 |
Android 测试文字编码格式 |
微信小程序支付 |
安卓权限记录 |
知乎之自动养号 |
【Android Jetpack】DataStore |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 3:22:37- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |