androidkotlinandroid-databindingkaptandroid-binding-adapter

Custom BindingAdapter with 2 parameteres and requireAll throws KaptExecution


This is the error I got:

> Task :app:kaptDevDebugKotlin FAILED
  location: package ...app.databinding
FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:kaptDevDebugKotlin'.
> A failure occurred while executing org.jetbrains.kotlin.gradle.internal.KaptExecution
   > java.lang.reflect.InvocationTargetException (no error message)

This is my custom BindingAdapter:

@Suppress("unused")
object BindingAdapters {

    @JvmStatic
    @BindingAdapter(value = ["isVisible", "hide"], requireAll = false)
    fun setVisible(view: View, show: Boolean?, hide: Boolean?) {
        view.visibility = if (show != false) View.VISIBLE else if (hide != false) View.INVISIBLE else View.GONE
    }
...
}

Usage in layout:

<include
    layout="@layout/view_loading_small"
    isVisible="@{viewModel.isLoading()}" ... />

Where:

private val _isLoading = MutableLiveData<Boolean>(false)
val isLoading: LiveData<Boolean> = _isLoading

I don't know what's happening, I've always used this method without problem. Today I've added the "hide" parameter and BAM KaptExecution InvocationTargetException.
The only workaround is changing my BindingAdapter object to:

    @JvmStatic
    @BindingAdapter(value = ["isVisible", "hide"], requireAll = false)
    fun setVisible(view: View, show: Boolean?, hide: Boolean?) {
        view.visibility = if (show != false) View.VISIBLE else if (hide != false) View.INVISIBLE else View.GONE
    }

    @JvmStatic
    @BindingAdapter(value = ["isVisible"])
    fun setVisible(view: View, show: Boolean) {
        setVisible(view, show, false)
    }

But this makes no sense, isn't the requireAll = false supposed to solve this? What am I missing here?


Solution

  • When you include a layout and want to change it visibility, you should do it via parameters. Following your example, your layout view_loading_small should have this:

    <data>
            <variable
                name="visible"
                type="boolean" />
        </data>
    

    Note: Add isVisible="@{visible}" on the view that you want to change visibility

    And your include:

    <include
        layout="@layout/view_loading_small"
        app:visible="@{viewModel.isLoading()}" ... />
    

    With this you should have no problems anymore. Also you can remove this:

     @JvmStatic
        @BindingAdapter(value = ["isVisible"])
        fun setVisible(view: View, show: Boolean) {
            setVisible(view, show, false)
        }
    

    One last thing, there’s a core-ktx extension function called isVisible:

    inline var View.isVisible: Boolean
        get() = visibility == View.VISIBLE
        set(value) {
            visibility = if (value) View.VISIBLE else View.GONE
        }
    

    So to be 100% safe, I think its probably a good idea to name your custom function with something else.

    Hope it helps! Regards!