【问题标题】:More fun with Kotlin delegatesKotlin 代表更有趣
【发布时间】:2017-06-30 11:03:39
【问题描述】:

如果您知道 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 :(

知道我能不能得到它吗?

【问题讨论】:

  • 考虑将您的解决方案作为答案发布,而不是作为问题的更新。这将有助于未来的读者并避免混淆。谢谢。

标签: delegates kotlin android-lifecycle android-databinding


【解决方案1】:

您可以access the delegate object 的属性并从中获取MutableLiveData&lt;T&gt;

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&lt;KotlinLiveData&lt;String&gt;&gt; 调用不是类型安全的:它只能检查委托是 KotlinLiveData&lt;*&gt;,但不能检查其类型参数是 String

【讨论】:

    【解决方案2】:

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

    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&lt;String&gt;{...})

    someViewModel.name = "Kowalski, Leon"

    按预期工作

    这个类支持使用 LiveData 和 Android 数据绑定。

    【讨论】:

      【解决方案3】:

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

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

      那么你可以在课堂上使用实时数据,例如:

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

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

      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;
      

      【讨论】:

      • 第一个建议不允许name="something",因为它期望KotlinLiveData&lt;String&gt;。第二个建议当然可行,但完全不切实际,因为我需要在代码中的许多不同位置为该值注册观察者...
      • @ssuukk 为什么第一种方法不能?您也可以在第二种方法中懒惰 nameObservername 属性类型的第一种方法是 String
      猜你喜欢
      • 2019-07-23
      • 1970-01-01
      • 2022-08-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-19
      • 2015-11-30
      相关资源
      最近更新 更多