76

I am trying to set custom attribute using the Android DataBinding Library in my Kotlin project like this:

Layout

<ImageView
    android:id="@+id/imgView”
    android:layout_width="40dp"
    android:layout_height="40dp"
    android:layout_gravity="center"
    android:adjustViewBounds="true"
    app:imageUrl="@{segment.url}"/>
                            

Code

class Utils {
    companion object {
        @BindingAdapter("bind:imageUrl")
        @JvmStatic
        fun loadImage(view: ImageView, url:String) 
        {Picasso.with(view.context).load(url).error(R.drawable.error).into(view)}
    }
}

    

    

The runtime error I get is:

A BindingAdapter in in <package.Utils.Companion> is not static and requires an object to use, retrieved from the DataBindingComponent. If you don't use an inflation method taking a DataBindingComponent, use DataBindingUtil.setDefaultComponent or make all BindingAdapter methods static.

Any pointers to solve it?

This happens only for custom attributes. The rest of the databindings work fine

7 Answers 7

125

Just keep function on the top level, no class or companion object needed, it will work since top-level functions in Kotlin translated to static member functions of Class named as FileNameKt unless overridden by @file:JvmName annotation

@BindingAdapter("imageUrl")
fun loadImage(view: ImageView, url:String) { ... }

One more option is to annotate Extension Function as @BindingAdapter, it will work since in bytecode signature will exactly match signature expected by DataBindings(generated method will still accept an object of the extended class as the first argument), the function should remain top level as well

@BindingAdapter("imageUrl")
fun ImageView.loadImage(url:String) { ... }

One more option is to combine BindingAdapter with the extension property like following:

@set:BindingAdapter("visible")
var View.visible
    get() = visibility == VISIBLE
    set(value) {
        visibility = if (value) VISIBLE else GONE
    }
Sign up to request clarification or add additional context in comments.

5 Comments

This answer is still giving me error. Lovis' answer worked for me.
What about lambdas? How can I assign lambda function in xml layout for custom BindingAdapter in Kotlin?
@ВладимирШироков yes you can, same as onClick works for Views in XML, you'll just need proper SAM class/interface developer.android.com/reference/android/databinding/…
What about the use of @JvmStatic?
@IgorGanapolsky all top-level functions is static so you don't need to declare it as @JvmStatic
43

Try switching the order of the annotations. It seems to fix the issue:

class Utils {
    companion object {
        @JvmStatic @BindingAdapter("imageUrl")
        fun loadImage(view: ImageView, url:String) { ... } 
    }
} 

The problem is that the databindng compiler uses getCompanion().loadImage otherwise*.
You can verify this in the generated com.your.package.databinding.*Binding class

* After playing around a bit I noticed that this has nothing to do with the order of the annotations, but seems to be random. It seems to change whenever I hit "rebuild". It might be a bug in kapt or in the kotlin compiler

6 Comments

Same here, changing the order does not help.
I put a kotlin bug report up youtrack.jetbrains.com/issue/KT-14417
Binding look for static method and on providing @JvmStatic inside companion object fixes the problem
Why do we have to have companion object?
@IgorGanapolsky nobody said you have to (see accepted answer), but that's how the question was asked.
|
14

Adding @JvmStatic after @BindingAdapter("imageUrl") fixed my problem.

For ex:

    @BindingAdapter("android:visibility")
    @JvmStatic
    fun setVisibility(view: View, visible: Boolean) {
        view.visibility = if (visible) View.VISIBLE else View.GONE
    }
}

Comments

3

Or using extension:

@BindingAdapter("imageUrl")
fun ImageView.setImageUrl(url: String?) {
    Picasso.with(context).load(url).into(this)
}

Now you can use this function anywhere else

2 Comments

You need @JvmStatic
@IgorGanapolsky you need '@JvmStatic' only if you are going to call it from Java code, it's for interop only. kotlinlang.org/docs/reference/java-to-kotlin-interop.html
3

This is working for me. Please find it below..

Add in gradle:

apply plugin: 'kotlin-kapt'

dependencies {
 kapt "com.android.databinding:compiler:3.1.4"
}

Add in POJO:

companion object {
  @BindingAdapter("image")
    @JvmStatic
         fun loadImage(view: ImageView, imageUrl: String) {

             //am Using Glide
Glide.with(view.context).setDefaultRequestOptions(RequestOptions().circleCrop())
                 .load(imageUrl).into(view)
         }
     }

In Layout:

Add bind:image="@{movies.imageUrl}

<ImageView 
  android:id="@+id/imageView"
  android:layout_width="100dp"
  android:layout_height="100dp"
  bind:image="@{movies.imageUrl}/>

6 Comments

Why do you have back-ticks around @BindingAdapter?
@igorganapolsky sorry.. Typo
There is absolutely no need for companion object with BindingAdapter
we should give companion object.. bcz we use @JvmStatic. otherwise we get an error.
@JvmStatic is not a requirement
|
2

The function(loadImage) need to put in object(Singleton in java) not in class and set @JvmStatic before @BindingAdapter("imageUrl") like this :

<ImageView
android:id="@+id/imgView”
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center"
android:adjustViewBounds="true"
imageUrl="@{segment.url}"/>

   @JvmStatic
   @BindingAdapter("bind:imageUrl")
   fun ImageView.loadImage( url:String) {
Picasso.with(this.context).load(url).error(R.drawable.error).into(this)
}

2 Comments

This requires companion object
'@JvmStatic' handle that, '@JvmStatic' its like companion object !
2

This worked for me

object ImageUtils {

        @JvmStatic @BindingAdapter("imageUrl")
        fun ImageView.loadImage(url: String?){
                GlideHelper.loadImage(url,this)
        }
}

in xml like this:

imageUrl="@{file.thumbnailLink}"

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.