使用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的类可以回归到单行变量声明:

Then, the class which extends BaseObservable could go back to having one-line variable declarations:

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

问题在于Foo类中没有@Bindable注解,因此bar的属性ID在BR中不会生成。 我不知道是否有其他注解或方法可以生成该属性ID。

希望能得到任何指导。

3个回答

20

您可以在不提供主体的情况下注释默认的 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)
}

3

除了接受的答案之外,有时您需要在构造函数中传递变量。这也很容易实现。

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

有时我们需要使用parcel来保存对象,我在使用委托时遇到了一些问题,所以代码看起来像这样:

@Parcelize
class Foo(private var _bar: String) : BaseObservable(), Parcelable {
    @IgnoredOnParcel
    @get:Bindable var bar 
    get() =  _bar
    set(value) {
        _bar = value
        notifyPropertyChanged(BR.bar)
    }
}

0

我曾考虑使用androidx.databinding.ObservableField包装我的字段。然而,从Kotlin代码中读取值为field.get()并写入值为field.set(value)是相当烦人的。此外,如果您将其与Retrofit或Room Database一起使用,则需要特殊的转换器进行序列化。

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


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("")
    @get:Bindable var password: String by ObservableField("", BR.password)
}



网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接