Android开发常用Kotlin高级语法
一、扩展函数与扩展属性:为系统类 “量身定制” 工具方法
Kotlin 的扩展机制允许为现有类(包括 Java 类)添加新功能,无需继承或修改原类。这在 Android 开发中尤其适合封装高频重复操作(如 View 操作、上下文获取)。
1.1 为 View 添加扩展函数:简化 UI 操作
Android 中操作 View 时,常需要处理可见性、点击事件等重复逻辑。通过扩展函数可以将这些逻辑封装,提升代码简洁性。
// 扩展函数:快速切换View可见性
fun View.setVisible(visible: Boolean) {visibility = if (visible) View.VISIBLE else View.GONE
}// 扩展函数:安全的点击事件(防重复点击)
fun View.setOnSingleClickListener(interval: Long = 500L, // 防重复点击间隔action: (View) -> Unit
) {var lastClickTime = 0LsetOnClickListener { view ->val currentTime = System.currentTimeMillis()if (currentTime - lastClickTime > interval) {lastClickTime = currentTimeaction(view)}}
}// 使用示例
val button = findViewById<Button>(R.id.btn_submit)
button.setVisible(true) // 替代 visibility = View.VISIBLE
button.setOnSingleClickListener { // 点击逻辑(500ms内仅触发一次)
}
1.2 为 Context 添加扩展属性:快速获取系统服务
Android 中获取系统服务(如LayoutInflater
、SharedPreferences
)需要调用getSystemService()
,通过扩展属性可以简化这一过程。
// 扩展属性:获取LayoutInflater
val Context.layoutInflater: LayoutInflaterget() = getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater// 扩展属性:获取默认SharedPreferences
val Context.defaultSp: SharedPreferencesget() = getSharedPreferences("app_prefs", Context.MODE_PRIVATE)// 使用示例(在Activity/Fragment中)
val inflater = layoutInflater // 直接使用扩展属性
val sp = defaultSp.edit().putString("user", "douban").apply()
二、作用域函数:优雅处理对象作用域
Kotlin 提供let
、run
、with
、apply
、also
等作用域函数,用于在特定作用域内操作对象。选择正确的函数可提升代码可读性。
1.1 作用域函数对比与最佳实践
函数 | 适用场景 | 返回值 | 内部用this 还是it |
---|---|---|---|
let | 对对象执行转换或操作,处理null 安全 | 最后一行表达式 | it (单个参数) |
run | 对象配置 + 计算返回值(需同时处理配置和结果) | 最后一行表达式 | this (对象自身) |
with | 对单个对象执行多个操作(类似run ,但通过参数传递对象) | 最后一行表达式 | this (对象自身) |
apply | 对象配置(无需返回值,仅需修改对象属性) | 对象自身 | this (对象自身) |
also | 对对象执行副作用操作(如日志、统计,不影响对象本身) | 对象自身 | it (单个参数) |
Android 开发中的典型用例:
// apply:配置View属性(返回View自身,适合链式调用)
val textView = TextView(context).apply {text = "Hello Douban"textSize = 16fsetTextColor(ContextCompat.getColor(context, R.color.primary))layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT)
}// let:处理可能为null的值(安全调用链)
intent?.extras?.let { extras -> val userId = extras.getString("user_id")userId?.let { loadUser(it) } // 嵌套let处理多级null
}// also:记录对象状态(不修改对象)
user.also { Log.d("User", "Loaded user: ${it.name}")
}.run { updateUI(this) // 继续对user执行操作
}
三、object
的核心用法
3.1 单例类(Singleton)
使用 object
关键字可以直接定义一个单例类,无需手动实现单例模式的样板代码。
// 定义单例类
object AppSettings {// 成员变量var theme: String = "light"var isDarkMode: Boolean = false// 成员函数fun saveSettings() {// 保存配置到本地}fun loadSettings() {// 从本地加载配置}
}// 使用单例(直接通过类名访问)
AppSettings.theme = "dark"
AppSettings.saveSettings()
特点:
- 全局唯一实例,由 Kotlin 编译器自动生成线程安全的单例实现。
- 可继承类或实现接口,但不能有构造函数(因为无法实例化)。
3.2 对象表达式(匿名内部类)
object
可用于创建匿名类的实例,常用于实现接口或继承类的一次性对象。
// 示例1:实现接口
val listener = object : View.OnClickListener {override fun onClick(v: View) {// 处理点击事件}
}// 示例2:继承类并扩展
val customRunnable = object : Runnable {var counter = 0override fun run() {counter++println("Running $counter times")}
}
应用场景:
- 替代 Java 中的匿名内部类(如点击监听器、回调接口)。
- 临时需要的对象(如单元测试中的 mock 对象)。
四、密封类与数据类:构建安全的状态模型
密封类(Sealed Class
)定义受限的类层次结构,适合表示有限的状态类型(如加载状态、网络请求结果);数据类(Data Class
)自动生成equals()
、hashCode()
等方法,适合表示数据模型。
4.1 密封类:实现状态机(State Machine)
在 MVVM 架构中,常用密封类表示 UI 状态(加载中、成功、失败),确保状态覆盖全面,避免遗漏。
// 密封类:定义网络请求状态
sealed class UserState {object Loading : UserState() // 加载中data class Success(val user: User) : UserState() // 成功(携带数据)data class Error(val exception: Throwable) : UserState() // 失败(携带异常)
}// ViewModel中更新状态
class UserViewModel : ViewModel() {private val _state = MutableLiveData<UserState>()val state: LiveData<UserState> = _statefun loadUser() {_state.value = UserState.Loading // 触发加载状态viewModelScope.launch {try {val user = fetchUser() // 异步获取数据_state.value = UserState.Success(user) // 更新为成功状态} catch (e: Exception) {_state.value = UserState.Error(e) // 更新为失败状态}}}
}// Activity中根据状态更新UI(配合when表达式,确保覆盖所有情况)
lifecycleScope.launch {viewModel.state.collect { state ->when (state) {is UserState.Loading -> showLoading()is UserState.Success -> showUser(state.user)is UserState.Error -> showError(state.exception)}}
}
4.2 数据类:简化数据模型与 Parcelable 集成
数据类默认生成copy()
、componentN()
等方法,适合表示结构化数据。结合@Parcelize
注解可快速实现Parcelable
接口(用于Intent
传参)。
// 数据类(自动生成equals、hashCode、toString)
@Parcelize // 需要添加kotlin-parcelize插件
data class User(val id: String,val name: String,val age: Int,val isVip: Boolean = false
) : Parcelable// 使用示例:通过Intent传递User对象
val user = User(id = "1", name = "Douban", age = 10)
val intent = Intent(context, DetailActivity::class.java).apply {putExtra("user", user) // 直接传递Parcelable对象
}
startActivity(intent)// 在DetailActivity中获取数据
val user = intent.getParcelableExtra<User>("user")
五、内联函数与具体化类型参数:突破泛型擦除限制
内联函数(inline
)将函数体直接插入调用处,减少函数调用开销;具体化类型参数(reified
)允许在运行时访问泛型类型,解决 Java 泛型擦除问题。
5.1 具体化类型参数:简化泛型类型检查
在 Android 中,常需要根据泛型类型动态创建对象或解析数据(如 JSON 反序列化),具体化类型参数可直接获取类型信息。
// 内联函数:通过反射获取泛型类型
inline fun <reified T> Gson.fromJson(json: String): T {return fromJson(json, T::class.java) // T::class.java 可获取具体类型
}// 使用示例(无需手动传递Type)
val user: User = gson.fromJson(jsonString) // 内联函数:启动Activity(泛型指定目标类)
inline fun <reified T : Activity> Context.startActivity() {startActivity(Intent(this, T::class.java))
}// 使用示例
startActivity<MainActivity>() // 替代 startActivity(Intent(this, MainActivity::class.java))
六、协程 (Coroutines):Android 异步编程的 “标准答案”
Android 异步编程中协程的完整实战示例-CSDN博客
七、lazy与lateinit语法对比
7.1 lazy 示例
// 单线程懒加载(Android 主线程)
val expensiveObject: ExpensiveObject by lazy(LazyThreadSafetyMode.NONE) {ExpensiveObject() // 首次访问时执行初始化
}// 多线程安全懒加载(默认模式)
val config: AppConfig by lazy {loadConfigFromDisk() // 自动加锁保证线程安全
}
7.2 lateinit 示例
// 在 Activity 中延迟初始化 ViewModel
lateinit var viewModel: MyViewModeloverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)viewModel = ViewModelProvider(this).get(MyViewModel::class.java)// 必须在使用 viewModel 前初始化
}
7.3 关键差异详解
- lazy:只能用于
val
(只读属性),因为其内部实现通过委托管理初始化值,初始化后不可修改。 - lateinit:只能用于
var
(可变属性),因为需要在后续代码中手动赋值。
相关文章:
Android开发常用Kotlin高级语法
一、扩展函数与扩展属性:为系统类 “量身定制” 工具方法 Kotlin 的扩展机制允许为现有类(包括 Java 类)添加新功能,无需继承或修改原类。这在 Android 开发中尤其适合封装高频重复操作(如 View 操作、上下文获取&…...

输入ifconfig,发现ens33不见了,无法连接至虚拟机
输入ifconfig,发现ens33不见了,无法连接至虚拟机 输入ifconfig,发现ens33不见了,无法连接至虚拟机 输入ifconfig,发现ens33不见了,无法连接至虚拟机 当输入ifconfig,发现少了ens33,无…...
Android Stdio 编译 文件生成,以及Gradle
一、生成调试版 APK(无需签名) 适用于测试阶段,可直接安装到模拟器或真机调试。 编译项目 确保项目无错误(菜单栏 → Build → Make Project 或按 Ctrl F9)。 生成 APK 点击菜单栏 Build → Generate App Bundles o…...
前端面试准备-4
1.React Router的history模式中,push和replace有什么区别 都是用于页面导航,但是他们对浏览器历史记录的处理不一样。 ①:push是在浏览历史栈里加入一条新的浏览历史,点击返回键会返回上一个页面 ②;replace是替换当前历史记录…...
AI赋能金融风控:基于机器学习的智能欺诈检测系统实战教程
引言 在数字化转型浪潮中,金融欺诈手段呈现智能化、隐蔽化趋势。传统规则引擎已难以应对复杂多变的欺诈模式,而机器学习技术通过自动学习数据特征,正在重塑金融风控体系。本文将基于Python生态,以信用卡欺诈检测为切入点…...

Java虚拟机内存区域划分
Java虚拟机内存区域划分 Java虚拟机(JVM)的内存区域划分主要分为五个部分: 程序计数器:程序计数寄存器,给CPU使用本地方法栈:为JVM使用到的Native方法服务方法区:存储的是编译后的.class文件堆…...
如何下载python的第三方类库
无论是在cmd中(使用python环境),还是在Anaconda Prompt中(使用虚拟环境),都可以通过pip命令进行下载python的第三方类库。 pip install packagename --default-timeout600 -i https://mirrors.tuna.tsingh…...
Redis击穿,穿透和雪崩详解以及解决方案
在 Java 开发中,Redis 作为常用的缓存中间件,可能会面临击穿、穿透、雪崩这三类经典问题。以下是对这三个问题的详细解析及对应的 Java 解决方案: 一、Redis 缓存击穿(Cache Breakdown) 问题描述 定义:大…...

网络渗透基础:信息收集
1.信息收集 whois xx.com 域名注册信息 注册人、电话、email Whois.chinaz.com kali自带whois工具 域名备案信息 Beian.miit.gov.cn Tianyancha.com Icp.chinaz.com 爱站 Sou.xiaolanben.com 2.子域名收集 收集方式 枚举:基于字典搜索引擎:googleh…...

[SAP] 如何查询当前屏幕的Tcode?
事务代码Tcode是SAP中到达特定屏幕的快捷路径 如何查询以下屏幕的事务码Tcode? 要浏览当前所使用的屏幕的事务码,可以选择System | Status 这里的事务代码是[VA22],它是Change Quotation的事务代码...

ZigBee 协议:开启物联网低功耗通信新时代
在物联网蓬勃发展的时代,无线通信技术犹如连接万物的桥梁,而 ZigBee 协议以其独特的优势,在众多通信协议中脱颖而出,成为构建低功耗、可靠物联网网络的关键技术之一。 一、ZigBee 协议的起源与发展 ZigBee 这个名字充满了自然的灵…...

JavaScript 模块系统:CJS/AMD/UMD/ESM
文章目录 前言一、CommonJS (CJS) - Node.js 的同步模块系统1.1 设计背景1.2 浏览器兼容性问题1.3 Webpack 如何转换 CJS1.4 适用场景 二、AMD (Asynchronous Module Definition) - 浏览器异步加载方案2.1 设计背景2.2 为什么现代浏览器不原生支持 AMD2.3 Webpack/Rollup 如何处…...

STM32F407寄存器操作(ADC非连续扫描模式)
1.前言 书接上回,在看手册的时候我突然发现手册上还描述了另一种ADC扫描模式,即非连续扫描模式,想着连续扫描模式都已经探索过了,那就顺手把非非连续模式研究一下吧。 2.理论 我们先看看手册,这里我就以规则通道举例…...
生产系统中TongWeb故障应急处理办法
本文档主要说明在上线正式运行的系统中,若TongWeb或部署在TongWeb上的应用出现问题时,现场维护人员或在现场的TongWeb支持人员应当采取的处理步骤。 工作基本原则: 任何操作必须经过项目相关负责人同意后进行,禁止在未允许的情况…...

PHP学习笔记(十一)
类常量 可以把在类中始终保持不变的值定义为常量,类常量的默认可见性是public。 接口中也可以定义常量。 可以用一个变量来动态调用类,但该变量的值不能为关键字 需要注意的是类常量只为每个类分配一次,而不是为每个类的实例分配。 特殊的…...
PyTorch中 torch.utils.data.DataLoader 的详细解析和读取点云数据示例
一、DataLoader 是什么? torch.utils.data.DataLoader 是 PyTorch 中用于加载数据的核心接口,它支持: 批量读取(batch)数据打乱(shuffle)多线程并行加载(num_workers)自…...

直线模组在手术机器人中有哪些技术挑战?
手术机器人在现代医疗领域发挥着越来越重要的作用,直线模组作为其关键部件,对手术机器人的性能有着至关重要的影响。然而,在手术机器人中使用直线模组面临着诸多技术挑战,具体如下: 1、高精度要求:手术…...

RK3568DAYU开发板-平台驱动开发--UART
1、程序介绍 本程序是基于OpenHarmony标准系统编写的平台驱动案例:UART 系统版本:openharmony5.0.0 开发板:dayu200 编译环境:ubuntu22 部署路径: //sample/06_platform_uart 2、基础知识 2.1、UART简介 UART指异步收发传输器(Univer…...
ubuntu 安装 Redis 5.0.8 的完整步骤
以下是根据前面的沟通记录整理的完整安装过程和依赖项,确保在 Ubuntu 22 上成功安装 Redis 5.0.8。 安装 Redis 5.0.8 的完整步骤 1. 安装依赖 在编译和运行 Redis 之前,需要安装一些必要的工具和库: sudo apt update sudo apt install bu…...

制造企业搭建AI智能生产线怎么部署?
制造商需要精准协调生产和发货,确保订单及时交付。MES、ERP、CRM 系统与生产线集成,对生产管理流程、物料跟踪、品控、确定货期至关重要。如果某个系统发生延迟或者效率低下,会在造成整个生产环节停滞,影响最终交付,导…...

深度学习驱动的超高清图修复技术——综述
Deep Learning-Driven Ultra-High-Definition Image Restoration: A Survey Liyan Wang, Weixiang Zhou, Cong Wang, Kin-Man Lam, Zhixun Su, Jinshan Pan Abstract Ultra-high-definition (UHD) image restoration aims to specifically solve the problem of quali…...
unix/linux source 命令,其内部结构机制
要理解 source (或 .) 命令的内部结构机制,我们需要戴上“操作系统”和“解释器设计”的眼镜,深入到 Shell 如何管理其状态以及如何执行命令的层面。 虽然我们无法直接看到 Shell 内部的 C 代码(除非我们去阅读 Bash 或 Zsh 的源码),但我们可以基于其行为和操作系统的原理…...
【LLM】FastAPI入门教程
note FastAPI 是一个现代的、快速(高性能)的 Web 框架,用于构建 API(应用程序编程接口)。它基于 Python 3.7,使用了 Python 类型提示(type hints),并且具有自动化的文档…...
进程同步机制-信号量机制-记录型信号量机制中的的wait和signal操作
wait和signal是记录型信号量机制中用于实现进程同步与互斥的两个重要操作, wait 操作 wait(semaphores *S) {S->value --;if (S->value<0) block(S->list) }请求资源:S->value --; 这一步表示进程请求一个单位的资源,将信号…...
gitlib 常见命令
git clone <项目URL> # 从 GitLab 拉取代码到本地 git status 查看状态 git diff 文件路径 查看修改位置 git diff 文件路径 查看修改位置 black -l 180 路径 格式化文件 git add 路径 (可以多个) 添加修改到暂存区 git commit -m “提交说明…...

Azure DevOps 管道部署系列之二IIS
本博客旨在提供如何使用 Azure DevOps YAML 管道部署到虚拟机上的 IIS 的实用指南。 开始之前,您需要做好以下准备: 您拥有要部署的服务器的访问权限以及 PowerShell 的管理员访问权限。您拥有要部署的远程服务器的互联网访问权限。您拥有在服务器上安装 .NET Core 托管包的…...

Vue.js教学第十七章:Vue 与后端交互(一),Axios 基础
Vue 与后端交互(一):Axios 基础 在现代前端开发中,Vue 应用通常需要与后端 API 进行数据交互,以实现动态数据的获取和提交。Axios 是一个基于 Promise 的 HTTP 客户端,广泛用于 Vue 项目中与后端进行通信。本文将深入讲解 Axios 的基本用法,包括如何通过 Axios 发送 GE…...

人工智能浪潮下,制造企业如何借力DeepSeek实现数字化转型?
一、DeepSeek技术概述 DeepSeek,凭借其强大的深度学习和自然语言处理能力,能够理解复杂问题并提供精准解决方案。它不仅能够作为学习、工作、生活的助手,满足用户在不同场景下的需求,更能在制造业中发挥重要作用。通过自然语言交…...
NodeJS全栈开发面试题讲解——P2Express / Nest 后端开发
✅ 2.1 Express 的中间件机制?如何组织一个 RESTful API 项目? 面试官好,我来讲讲 Express 的中间件机制,它是 Express 架构的核心,也是组织 RESTful 项目的基础。 🧩 什么是中间件? 中间件&am…...

从线性代数到线性回归——机器学习视角
真正不懂数学就能理解机器学习其实是个神话。我认为,AI 在商业世界可以不懂数学甚至不懂编程也能应用,但对于技术人员来说,一些基础数学是必须的。本文收集了我认为理解学习本质所必需的数学基础,至少在概念层面要掌握。毕竟&…...