与 Kotlin 代表一起玩得更开心

More fun with Kotlin delegates

如果您知道 Google 的实验性 Android 架构组件,您可能知道 MutableLiveData。为了让它使用起来更有趣,我带来了:

class KotlinLiveData<T>(val default: T) {
    val data = MutableLiveData<T>()

    operator fun getValue(thisRef: Any?, property: KProperty<*>):T {
        return data.value ?: default
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value:T) {
        if (Looper.myLooper() == Looper.getMainLooper()) {
            data.value = value
        } else {
            data.postValue(value)
        }
    }
}

然后我可以:

var name : String by KotlinLiveData("not given")
name = "Chrzęszczybrzęczykiewicz"

但是,唉 - 这使得需要 data,即注册 Observer 无法访问:

name.data.observe(this, nameObserver) // won't work :(

知道我是否能以某种方式得到它吗?

您可以实现的最简单方法是将委托人分配给一个字段,例如:

@JvmField val dataOfName =  KotlinLiveData("not given")
var name : String by dataOfName

然后您可以使用 class 中的实时数据,例如:

dataOfName.data.observe(this, nameObserver)
name = "Chrzęszczybrzęczykiewicz"

OR 你可以写一些语法糖,例如:

var name : String by live("not given").observe(this, nameObserver)

注意你也可以懒惰地制作nameObserver,例如:

val observers by lazy{mutableListOf<Observer>()}
var name : String by live("not given").observe(this){data->
    observers.forEach{it.dataChanged(data)}
}

然后您可以执行如下操作:

observers+= nameObserver;

name = "Chrzęszczybrzęczykiewicz"

observers-= nameObserver;

您可以 属性 的 并从中获取 MutableLiveData<T>

inline fun <reified R> KProperty<*>.delegateAs<R>(): R? {
    isAccessible = true
    return getDelegate() as? R
}

那么用法是:

::name.delegateAs<KotlinLiveData<String>>?.data?.observe(this, nameObserver)

要引用成员 属性,请使用 this::namesomeInstance::name

此解决方案要求您将 Kotlin 反射 API、kotlin-reflect 添加为项目的依赖项。此外,由于类型擦除,.delegateAs<KotlinLiveData<String>> 调用不是类型安全的:它只能检查委托是 KotlinLiveData<*> 而不是它的类型参数是 String.

感谢 hotkey 的解决方案,这里有一些更好的代码:

class KotlinLiveData<T>(val default: T, val liveData : MutableLiveData<T>? = null) {
    val data = liveData ?: MutableLiveData<T>()

    operator fun getValue(thisRef: Any?, property: KProperty<*>):T {
        return data.value ?: default
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value:T) {
        if (Looper.myLooper() == Looper.getMainLooper()) {
            data.value = value
        } else {
            data.postValue(value)
        }
    }
}

inline fun <reified R> KMutableProperty0<*>.getLiveData(): MutableLiveData<R> {
    isAccessible = true
    return (getDelegate() as KotlinLiveData<R>).data
}

inline fun <reified R> KMutableProperty0<*>.observe(owner: LifecycleOwner, obs : Observer<R>) {
    isAccessible = true
    (getDelegate() as KotlinLiveData<R>).data.observe(owner,obs)
}

现在我可以:

someViewModel::name.observe(myActivity, Observer<String>{...})

someViewModel.name = "Kowalski, Leon"

按预期工作

此 class 支持使用 LiveData 和开箱即用的 Android 数据绑定。