-->

Data Binding: ObservableField with lambda value do

2019-08-08 15:14发布

问题:

I'm trying to define the visibility of the View by calculating the lambda that takes one parameter as an argument. I'm using Kotlin, btw.

In my ViewModel I have:

    val customerPropVisibility: ObservableField<(KProperty1<Customer, *>) -> Int> = ObservableField(
        { _ ->
            // body of the lambda
        })

The binding expression for the View is the following:

     android:visibility="@{vm.customerPropVisibility.invoke(title)}"

vm and title are properly declared as variables in the data tag of the layout.

On compilation, I get two errors:

1) incompatible types: Object cannot be converted to Function1

2) incompatible types: Object cannot be converted to Integer

There is only one error of the first type and several errors of the second type. The number of the errors of the second type is the same as the number of invocations of the lambda in the layout xml file.

My attempts of solving the issue:

Obviously, the error of type 1 can be solved by overriding the get() method of the ObservableField (making the method return Function1 explicitly). This works, but is ugly and should be done by the compiler when it infers the type for customerPropVisibility. Definitely, something is wrong here.

The error of type 2 is a mystery to me, cause the function type (my lambda) explicitly returns Int.

I presume it has something to do with Kotlin/Java interoperability.

If you have stumbled upon the same issue, please share the experience of solving it.

EDIT:

Since this bug is not yet resolved, I use slightly different approach to achieve the same result:

Instead of setting the value of ObservableField to lambda, I set it to function reference (::getVisibility) like so:

fun getVisibility(prop: KProperty1<*, *>): Int = propVisibilityValues[prop] ?: View.GONE
val propVisibilityGetter = ObservableField(::getVisibility)

And whenever the propVisibilityValues changes I notify the propVisibilityGetter:

private val propVisibilityValues = ObservableArrayMap<KProperty1<*, *>, Int>().apply {
    addOnMapChangedCallback(object : ObservableMap.OnMapChangedCallback<ObservableMap<KProperty1<*, *>, Int>, KProperty1<*, *>, Int>() {
        override fun onMapChanged(p0: ObservableMap<KProperty1<*, *>, Int>?, p1: KProperty1<*, *>?) {
            propVisibilityGetter.notifyChange()
        }
    })
}

In XML layout file, the binding expression looks like:

android:visibility="@{vm.propVisibilityGetter.call(title)}"

Overall result: messy in the View Model, but clean binding expressions.