与 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::name
或 someInstance::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 数据绑定。
如果您知道 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::name
或 someInstance::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 数据绑定。