开源鸿蒙跨平台开发者社区 Type ‘androidx.compose.runtime.State<kotlin.Int>‘ has no method ‘getValue(Nothing?, KProperty...的解决

Type ‘androidx.compose.runtime.State<kotlin.Int>‘ has no method ‘getValue(Nothing?, KProperty...的解决

by关键字在Kotlin中的核心作用是将职责委托给另一个对象类委托:实现接口并将方法调用委托给另一个对象。属性委托:将属性的get/set逻辑委托给另一个对象,支持自定义和标准委托。这种设计使代码更加简洁、复用性更高,同时避免了样板代码。

地推  ·  2025-05-12 20:00:16 发布

1、写了一个委托by

val counter by viewModel.counter.collectAsStateWithLifecycle()
val derivedState by viewModel.derivedState.collectAsStateWithLifecycle()
  • 1.
  • 2.

 说明

上面代码用于在Jetpack Compose中收集ViewModel中的状态流,并在状态变化时自动重组UI。

counter:通过collectAsStateWithLifecycle()收集viewModel.counter的状态流,绑定生命周期。

derivedState:同理,收集viewModel.derivedState的状态流。

Type

Type 'androidx.compose.runtime.State<kotlin.Int>' has no method 'getValue(Nothing?, KProperty0<*>)', so it cannot serve as a delegate.
  • 1.

然后报上面的错误,并且不太好修复。

2、增加导入androidx.compose.runtime.getValue就可以解决

import androidx.compose.runtime.getValue
  • 1.

Type

我们可以发现错误消失了。

3、Kotlin中by的用法(ai)

在Kotlin中,by关键字主要用于两种场景:委托模式(Delegation)和属性委托(Property Delegation)。这两种机制都是Kotlin语言的重要特性,它们允许你在不编写大量样板代码的情况下复用行为和逻辑。

一、委托模式(Class Delegation)

委托模式是一种设计模式,允许类将其某些职责委托给另一个对象。Kotlin通过by关键字原生支持这一模式,使代码更加简洁。

1. 基本语法
interface Base {
    fun print()
}

class BaseImpl(val x: Int) : Base {
    override fun print() { println(x) }
}

class Derived(b: Base) : Base by b  // 通过by关键字将接口实现委托给b对象

fun main() {
    val b = BaseImpl(10)
    Derived(b).print()  // 输出: 10
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
2. 关键点说明
  • 接口委托Derived类实现了Base接口,但实际的实现被委托给了构造函数中传入的b对象。
  • 无需重写方法Derived类不需要显式实现print()方法,因为委托对象b已经实现了它。
  • 局部委托:你也可以选择性地重写某些方法,这些方法将覆盖委托对象的实现:
class Derived(b: Base) : Base by b {
    override fun print() { println("Overridden: ${b.x}") }  // 覆盖委托实现
}
  • 1.
  • 2.
  • 3.

二、属性委托(Property Delegation)

属性委托允许你将属性的get()set()逻辑委托给另一个对象,这在实现常见模式(如延迟初始化、可观察属性等)时特别有用。

1. 基本语法
class Example {
    var p: String by Delegate()  // 属性p的访问器委托给Delegate实例
}

class Delegate {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return "$thisRef, thank you for delegating '${property.name}' to me!"
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        println("$value has been assigned to '${property.name}' in $thisRef.")
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
2. 委托要求
  • getValue():对于只读属性(val),委托类必须提供getValue()方法。
  • setValue():对于可变属性(var),委托类必须同时提供getValue()setValue()方法。
  • 操作符重载:这两个方法都需要使用operator关键字标记。
3. 标准委托

Kotlin标准库提供了几种常用的委托:

① lazy() - 延迟初始化
val lazyValue: String by lazy {
    println("computed!")
    "Hello"
}

// 第一次调用时初始化
println(lazyValue)  // 输出: computed! Hello
// 后续调用直接使用缓存值
println(lazyValue)  // 输出: Hello
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
② observable() - 可观察属性
import kotlin.properties.Delegates

class User {
    var name: String by Delegates.observable("初始值") {
        property, oldValue, newValue ->
        println("${property.name}从$oldValue变为$newValue")
    }
}

val user = User()
user.name = "张三"  // 输出: name从初始值变为张三
user.name = "李四"  // 输出: name从张三变为李四
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
③ map委托 - 从Map读取属性
class User(val map: Map<String, Any?>) {
    val name: String by map  // 从map中读取"name"键的值
    val age: Int     by map  // 从map中读取"age"键的值
}

val user = User(mapOf(
    "name" to "John Doe",
    "age"  to 25
))

println(user.name)  // 输出: John Doe
println(user.age)   // 输出: 25
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

三、ViewModel中的by viewModels()

在Android开发中,你经常会看到这样的代码:

private val viewModel: MainViewModel by viewModels()
  • 1.

这是Kotlin委托的一种特殊应用,by viewModels()是AndroidX库提供的扩展函数,用于创建和获取ViewModel实例。它的工作原理是:

  • 通过委托模式,将ViewModel的创建和生命周期管理委托给ViewModelProvider
  • 自动处理ViewModel的作用域(如Activity或Fragment)。
  • 确保配置更改(如屏幕旋转)时ViewModel实例不会丢失。

四、总结

by关键字在Kotlin中的核心作用是将职责委托给另一个对象,它简化了两种重要模式:

  1. 类委托:实现接口并将方法调用委托给另一个对象。
  2. 属性委托:将属性的get/set逻辑委托给另一个对象,支持自定义和标准委托。

这种设计使代码更加简洁、复用性更高,同时避免了样板代码。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐

  • 浏览量 1033
  • 收藏 0
  • 0

所有评论(0)

查看更多评论 
已为社区贡献10条内容