相关文章推荐
小胡子的火锅  ·  Android ...·  1 月前    · 
俊秀的跑步机  ·  蓝牙mac地址-掘金·  1 年前    · 
严肃的柚子  ·  Android ...·  1 年前    · 

使用Kotlin、BaseObservable和自定义委托的Android数据绑定

13 人关注

我正在尝试编写一个自定义的委托,它可以清理Kotlin类中数据绑定的语法。 它将消除为我可能想要观察的每个属性定义一个自定义getter和setter的需要。

Kotlin中的标准实现似乎是这样的。

class Foo : BaseObservable() {
    var bar: String
         @Bindable get() = bar
         set(value) {
             bar = value
             notifyPropertyChanged(BR.bar)

显然,如果有大量的属性,这个类就会变得非常冗长。 我想做的是将其抽象为一个委托,就像这样。

class BaseObservableDelegate(val id: Int, private val observable: BaseObservable) {
     @Bindable
     operator fun getValue(thisRef: Any, property: KProperty<*>): Any {
         return thisRef
     operator fun setValue(thisRef: Any, property: KProperty<*>, value: Any) {
         observable.notifyPropertyChanged(id)

然后,扩展BaseObservable的类可以回到有单行变量声明的状态。

class Foo : BaseObservable() {
      var bar by BaseObservableDelegate(BR.bar, this)

问题是,如果Foo类中没有@Bindable注解,BR中就不会为bar生成propertyId。 我不知道有什么其他注解或方法可以生成该属性的ID。

希望得到任何指导。

android
kotlin
observable
android-databinding
RBusarow
RBusarow
发布于 2017-09-04
3 个回答
ephemient
ephemient
发布于 2022-06-20
已采纳
0 人赞同

你可以注释默认的getter或setter而不提供主体。

var bar: String by Delegates.observable("") { prop, old, new ->
    notifyPropertyChanged(BR.bar)
    @Bindable get

有一个捷径注释的使用地点目标它做同样的事情。

@get:Bindable var bar: String by Delegates.observable("") { prop, old, new ->
    notifyPropertyChanged(BR.bar)
    
Janusz Hain
Janusz Hain
发布于 2022-06-20
0 人赞同

对已接受的答案的补充 - 有时你需要在构造函数中传递变量。这也是很容易做到的。

class Foo(_bar: String) : BaseObservable() {
      @get:Bindable var bar by Delegates.observable(_bar) { _, _, _ ->
          notifyPropertyChanged(BR.bar)

有时我们必须使用parcel来保存对象,我在使用delegete时遇到一些问题,所以代码看起来是这样的。

@Parcelize
class Foo(private var _bar: String) : BaseObservable(), Parcelable {
    @IgnoredOnParcel
    @get:Bindable var bar 
    get() =  _bar
    set(value) {
        _bar = value
        notifyPropertyChanged(BR.bar)
    
Samuel Robert
Samuel Robert
发布于 2022-06-20
0 人赞同

我考虑为我的字段使用 androidx.databinding.ObservableField 包装器。然而,从Kotlin代码中读取 field.get() 和写入 field.set(value) 的值是相当烦人的。另外,如果你和Retrofit或Room Database一起使用,这种方法确实需要特殊的转换器进行序列化。

最后,我想出了下面的方法,它允许我在一行中定义变量,而不是公认的答案,并保持字段的默认类型,没有任何包装。感谢Kotlins的属性委托。现在,我不需要为序列化写转换器了,而且可以从数据库绑定中获得所有的好处。

class ObservableField<T : BaseObservable, V>(initialValue: V, private val fieldId: Int = -1) : ReadWriteProperty<T, V> { private var value: V = initialValue override fun getValue(thisRef: T, property: KProperty<*>): V { return value override fun setValue(thisRef: T, property: KProperty<*>, value: V) { this.value = value if (fieldId == -1) { thisRef.notifyChange() } else { thisRef.notifyPropertyChanged(fieldId) class Credential: BaseObservable() { var username: String by ObservableField("")