Android Kotlin - Binding adapter AK(android.widget.ImageView, java.lang.String) already exists for imageUrl

Viewed 2426

I have the following log error when I'm building an android app:

Binding adapter AK(android.widget.ImageView, java.lang.String) already exists for imageUrl! Overriding com.example.newsapp.utils.ImageUtils.Companion#loadImageFromUrl with com.example.newsapp.utils.ImageUtils#loadImageFromUrlwarning: Binding adapter AK(android.widget.ImageView, java.lang.String) already exists for imageUrl! Overriding com.example.newsapp.utils.ImageUtils.Companion#loadImageFromUrl with com.example.newsapp.utils.ImageUtils#loadImageFromUrl

The imageUrl attribute is:

class ImageUtils {
    companion object {

        @JvmStatic
        @BindingAdapter("imageUrl")
        fun ImageView.loadImageFromUrl(imageUrl: String?) {
            Glide.with(this).load(imageUrl).into(this)
        }
    }
}

and the xml file contains the following:

<ImageView
    android:id="@+id/articleImage"
    android:layout_width="158dp"
    android:layout_height="0dp"
    android:scaleType="centerCrop"
    app:imageUrl="@{article.urlToImage}"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    tools:ignore="ContentDescription"
    tools:srcCompat="@tools:sample/avatars" />
3 Answers

For Kotlin

I think the issue is due to how the Java class is generated fro your Kotlin class. If you decompile the code you can see the issue as it will define the adapter twice, once in a class and once in a companion class.

2 solutions:

Method 1: Object declaration

package myApp
// import omitted

companion object ImageUtilsBindingAdapter {

    @JvmStatic
    @BindingAdapter("imageUrl")
    fun ImageView.loadImageFromUrl(imageUrl: String?) {
        Glide.with(this).load(imageUrl).into(this)
    }
}

Method 2: Package function

package myApp;
// import omitted

@BindingAdapter("imageUrl")
fun ImageView.loadImageFromUrl(imageUrl: String?) {
    Glide.with(this).load(imageUrl).into(this)
}

You can read about this more here. https://medium.com/@hkhcheung/defining-android-binding-adapter-in-kotlin-b08e82116704

Credit to the Medium article author Herman Cheung.

It might sound strange but in my case issue caused because I forgot to supply data to the ViewModel using data binding.

actual function was

fun navigateToNextScreen(data: Data, index: Int) {
//navigation code here
}

The issue caused because of the below code

<androidx.cardview.widget.CardView
android:onClick="@{() ->viewModel.navigateToNextScreen(data)}"
/>

It was solved by passing all the required params like

<androidx.cardview.widget.CardView
android:onClick="@{() ->viewModel.navigateToNextScreen(data, index)}"
/>

So in case if you still face the issue after trying all the solutions on this post, I'll suggest you to check for your model classes and view model functions.

Building on @Vishal Naikawadi's answer, I found that this was caused for me by the binding adapter having multiple parameters and only one being used.

https://developer.android.com/topic/libraries/data-binding/binding-adapters#custom-logic

From the docs for databinding:

@BindingAdapter("imageUrl", "error")
fun loadImage(view: ImageView, url: String, error: Drawable) {
    Picasso.get().load(url).error(error).into(view)
}

You can use the adapter in your layout as shown in the following example. Note that @drawable/venueError refers to a resource in your app. Surrounding the resource with @{} makes it a valid binding expression.

<ImageView app:imageUrl="@{venue.imageUrl}" app:error="@{@drawable/venueError}" />

The adapter is called if both imageUrl and error are used for an ImageView object and imageUrl is a string and error is a Drawable. If you want the adapter to be called when any of the attributes is set, you can set the optional requireAll flag of the adapter to false, as shown in the following example:

@BindingAdapter(value = ["imageUrl", "placeholder"], requireAll = false)
fun setImageUrl(imageView: ImageView, url: String?, placeHolder: Drawable?) {
    if (url == null) {
        imageView.setImageDrawable(placeholder);
    } else {
        MyImageLoader.loadInto(imageView, url, placeholder);
    }
}

Conclusion:

Be sure to bind every parameter. I was only binding one of several which caused this same error.

Related