Kotlin 的延迟初始化委托属性 by lazy

Kotlin 的延迟初始化委托属性 by lazy 详细解释:


📖 代码拆解

kotlin 复制代码
private val viewModel: NewsViewModel by lazy {

可以拆分为几个部分:

部分 含义
private 私有访问修饰符,外部无法访问
val 只读属性(类似 Java 的 final)
viewModel 属性名称
: NewsViewModel 属性类型
by lazy 使用延迟初始化委托

🔄 lazy 的工作原理

1. 延迟初始化

kotlin 复制代码
// 使用 lazy 的写法
private val viewModel: NewsViewModel by lazy {
    AppModule.provideNewsViewModel()
}

等价的 Java 写法:

java 复制代码
private NewsViewModel viewModel;

private NewsViewModel getViewModel() {
    if (viewModel == null) {
        viewModel = AppModule.provideNewsViewModel();
    }
    return viewModel;
}

2. 执行时机

时机 说明
声明时 ❌ 不执行
第一次访问时 ✅ 执行初始化
后续访问 ✅ 直接返回缓存值

例子:

kotlin 复制代码
private val viewModel: NewsViewModel by lazy {
    println("初始化 ViewModel")  // 这行只会在第一次访问时执行
    AppModule.provideNewsViewModel()
}

fun onCreate() {
    println("onCreate 开始")
    // viewModel 还没初始化
    println(viewModel.newsList)  // 此时才初始化,打印 "初始化 ViewModel"
    println(viewModel.newsList)  // 直接返回缓存,不打印
}

💡 为什么使用 lazy

1. 性能优化

kotlin 复制代码
// 不使用 lazy(每次创建 MainActivity 都会初始化)
private val viewModel = AppModule.provideNewsViewModel()  // 立即执行

// 使用 lazy(只在第一次访问时初始化)
private val viewModel: NewsViewModel by lazy {
    AppModule.provideNewsViewModel()  // 延迟执行
}

2. 避免循环依赖

kotlin 复制代码
class MainActivity {
    private val viewModel by lazy { NewsViewModel(repository) }
    private val repository by lazy { NewsRepository() }
    
    // 如果不用 lazy,repository 还没初始化就传给 viewModel 会报错
}

3. 简化代码

kotlin 复制代码
// 不使用 lazy
private lateinit var viewModel: NewsViewModel

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    viewModel = AppModule.provideNewsViewModel()
}

// 使用 lazy
private val viewModel: NewsViewModel by lazy {
    AppModule.provideNewsViewModel()
}

🎯 在项目中的实际应用

完整代码:

kotlin 复制代码
class MainActivity : ComponentActivity() {

    // 延迟初始化 ViewModel
    private val viewModel: NewsViewModel by lazy {
        AppModule.provideNewsViewModel()
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            AndroidFireTheme {
                // 第一次访问 viewModel 时才初始化
                val selectedNews by viewModel.selectedNews.collectAsState()
                
                if (selectedNews != null) {
                    DetailScreen(news = selectedNews!!, onBack = { ... })
                } else {
                    HomeScreen(viewModel = viewModel, onNewsClick = { ... })
                }
            }
        }
    }
}

🔄 lazy vs lateinit 对比

特性 lazy lateinit
类型 只读(val 可变(var
初始化时机 第一次访问时 手动赋值
线程安全 默认线程安全 不安全
可空性 不可空 可空
适用场景 只读属性、延迟初始化 可变属性、依赖注入

💻 实际例子

例子1:普通延迟初始化

kotlin 复制代码
private val expensiveObject: ExpensiveObject by lazy {
    println("开始初始化...")
    Thread.sleep(2000)  // 模拟耗时操作
    ExpensiveObject()
}

fun test() {
    println("1")
    println(expensiveObject)  // 第一次访问,开始初始化
    println("2")
    println(expensiveObject)  // 第二次访问,直接返回缓存
    println("3")
}

// 输出:
// 1
// 开始初始化...
// ExpensiveObject@123
// 2
// ExpensiveObject@123
// 3

例子2:线程安全的 lazy

kotlin 复制代码
private val threadSafeValue by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
    // 确保只有一个线程执行初始化
    "thread-safe"
}

🎓 总结

要点 说明
作用 延迟初始化,只在第一次访问时执行
优势 性能优化、避免循环依赖、代码简洁
线程安全 默认线程安全(SYNCHRONIZED 模式)
适用场景 只读属性、初始化耗时、依赖其他属性

简单理解by lazy 就是"懒加载",用的时候才初始化,不用就不初始化,节省资源!

相关推荐
Coffeeee8 小时前
Android功耗优化,哪些代码会让你的机子发热又耗电
android·架构·kotlin
Android打工仔8 小时前
Kotlin 编译器是如何把 suspend 函数变成状态机的?
kotlin
Android打工仔8 小时前
一个 suspend 函数,为什么会变成一个普通函数?
kotlin
苦瓜花1 天前
【Kotlin】初入门
android·开发语言·kotlin
Kapaseker1 天前
Rust 是如何处理异常的
rust·kotlin
冬日砥砺前行1 天前
Kotlin 协程:几个曾经被我误解的点
kotlin
plainGeekDev3 天前
libs 目录 → Gradle 依赖管理
android·java·kotlin
监督者修3 天前
从零构建 GIS 数据引擎:方案驱动架构的设计与实践
android·架构·kotlin
urkay-4 天前
Kotlin Flow分类
android·开发语言·kotlin
alexhilton5 天前
Kotlin DSL深度解析:从Gradle脚本到构建你自己的DSL
android·kotlin·android jetpack