Más diversión con los delegates de Kotlin

Si conoces los Componentes de Arquitectura de Android experimentales de Google, probablemente conozcas MutableLiveData . Tratando de que sea un poco más divertido de usar, vine con:

 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) } } } 

Y luego puedo:

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

Pero, por desgracia, eso hace que los data necesarios, es decir, para registrar Observer inaccesibles:

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

Alguna idea si puedo conseguirlo de alguna manera?

Puede acceder al object delegado de la propiedad y get MutableLiveData<T> de él:

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

Entonces el uso es:

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

Para hacer reference a una propiedad miembro, use this::name o someInstance::name .

Esta solución requiere que agregue la API de reflexión Kotlin, kotlin-reflect , como una dependencia de su proyecto. Además, debido al borrado de tipo, la .delegateAs<KotlinLiveData<String>> no es segura para types: solo puede verificar que el delegado sea KotlinLiveData<*> pero no que su argumento de tipo sea String .

la manera más simple que puede lograr es hacer que el delegador en un campo, por ejemplo:

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

entonces puedes usar datos en vivo en la class, por ejemplo:

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

O puede escribir alguna syntax suglar, por ejemplo:

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

Tenga en count que también puede hacer nameObserver perezosamente, por ejemplo:

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

entonces puedes hacer algo como a continuación:

 observers+= nameObserver; name = "Chrzęszczybrzęczykiewicz" observers-= nameObserver; 

Gracias a la solución de teclas de acceso directo, aquí hay un código mejor:

 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) } 

Ahora puedo:

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

con

someViewModel.name = "Kowalski, Leon"

trabajando como se esperaba

Esta class permite usar LiveData con Android Data Binding de la caja.

  • UnsupportedOperationException El command "android" ya no está incluido en el SDK
  • Android Koltin pasa los valores del girador a la list mutable
  • Cómo extender desde una InnerClass en kotlin
  • Error ': app: kaptDebugKotlin' en la versión estable de android studio 3 con la habitación 1 (RC)
  • Redacción de request de networking con RX y Kotlin
  • ¿Cuáles son las classs comunes de plataforma en Kotlin?
  • ¿Por qué las expresiones Lambda se comportan de manera diferente para las classs de Kotlin y Java?
  • Problemas para get API de Meetup Token de acceso con modificación - Android
  • solo se permiten classs en el lado izquierdo de un literal de class al usar Mockito y kotlin
  • Petición multipartida con Retrofit @PartMap Error en Kotlin (Android)
  • GridLayout en Kotlin?