Невозможно использовать BindingAdapter в Котлине

Раньше я создавал DataBindingAdapter для создания пользовательских атрибутов xml в привязке данных.

object DataBindingAdapter {
    @BindingAdapter("android:src")
    fun setImageByRes(imageView: ImageView, @DrawableRes resId: Int) {
        imageView.setImageResource(resId)
    }
}

Он хорошо работал на Java. Но не работает в kotlin.

Насколько я понимаю, объект в kotlin похож на статический метод Java. Но он не работает в привязке данных.

java.lang.IllegalStateException: Required DataBindingComponent имеет значение null в классе FragmentBottomBarBinding. BindingAdapter в acr.browser.lightning.utils.DataBindingAdapter не является статическим и требует использования объекта, полученного из DataBindingComponent. Если вы не используете метод инфляции, использующий DataBindingComponent, используйте DataBindingUtil.setDefaultComponent или сделайте все методы BindingAdapter статическими.


person Khemraj Sharma    schedule 16.08.2018    source источник
comment
Вы пробовали @JvmStatic аннотацию на setImageByRes.   -  person Moinkhan    schedule 16.08.2018
comment
Если вы столкнулись с проблемами взаимодействия (Java вызывает код Kotlin), хорошим подходом является декомпиляция сгенерированного байт-кода в Java и просмотр, как выглядит результат. Это часто позволяет сразу понять, где несоответствие интерфейса.   -  person TheOperator    schedule 16.08.2018
comment
@Moinkhan JvmStatic сделал свое дело.   -  person Khemraj Sharma    schedule 16.08.2018
comment
Вы забыли @JvmStatic   -  person EpicPandaForce    schedule 16.08.2018
comment
Поскольку вы не ответили, я сделал вашу работу. Теперь вы можете ответить. Я отмечу это правильно, вы это заслужили.   -  person Khemraj Sharma    schedule 16.08.2018


Ответы (2)


Просто добавьте аннотацию @Jvmstatic к методу setImageByRes.

object DataBindingAdapter {
    @BindingAdapter("android:src")
    @JvmStatic
    fun setImageByRes(imageView: ImageView, @DrawableRes resId: Int) {
        imageView.setImageResource(resId)
    }
}

согласно @Jvmstatic документу.

Указывает, что для этого элемента необходимо сгенерировать дополнительный статический метод, если это функция. Если этот элемент является свойством, должны быть сгенерированы дополнительные статические методы получения/установки.

Короче говоря, метод объявлен в одном месте и используется на нескольких языках JVM. Если вы вызываете метод из Java, вы должны объявить его как @JvmStatic, потому что добавление аннотации @JvmStatic в одном месте позволит вам пропустить несколько ссылок .Companion в нескольких местах.

person Moinkhan    schedule 16.08.2018
comment
Если вы добавите немного информации о JvmStatic для новичков, будет здорово. - person Khemraj Sharma; 16.08.2018
comment
Привет @Moinkhan, как связать этот DataBindingAdapter с представлением или адаптером ресайклера? - person Milan Sheth; 25.09.2020

Нет. Объект в kotlin такой же, как синглтон. Я думаю, вам не нужно помещать его в объект. Просто создайте новый файл, скажем, BindingAdapters.kt, и вам не нужно писать какие-либо ключевые слова класса или объекта.

Это должно выглядеть так. Ничего больше. Если вам нужно больше функций, просто добавьте их ниже этой. Опять же, ключевое слово класса или скобки не нужны. Это будет глобальная функция. Возможно, вам также следует использовать ContextCompat для правильного получения resource с контекстом из imageView. И я бы предпочел назвать его иначе, чем android:src. Как насчет imageResBinder

@BindingAdapter("imageResBinder")
fun setImageByRes(imageView: ImageView, @DrawableRes resId: Int) {
    imageView.setImageResource(resId)
}

и после этого в вашем .xml файле

<android.support.v7.widget.AppCompatImageView
    style="@style/Image.SomeImageStyle"
    app:imageResBinder="@{viewModel.getImageRes()}" />
person Kebab Krabby    schedule 16.08.2018
comment
Если мне нужно, как я могу вызвать эту функцию из другого котлина? - person Khemraj Sharma; 16.08.2018
comment
Ты не можешь. Единственное, что вы можете сделать, это вызвать его из другого файла .xml, потому что его глобальный метод предназначен только для привязки данных. Так что вы не можете сказать, вызовите его во фрагменте onViewCreated(). Конечно, вы можете создать статический класс для загрузки ресурсов, но я думаю, что вам не следует этого делать, если вы используете привязку данных. Вы также можете поместить этот bindAdapter только в какой-либо класс модели: "> stackoverflow.com/questions/40845767/ - person Kebab Krabby; 16.08.2018
comment
Тогда я предпочту @JvmStatic, потому что может быть какая-то общая функция, которую может быть полезно вызывать из другого действия. - person Khemraj Sharma; 16.08.2018