How to databinding image loading with Glide?

13,230

Solution 1

You need to make url parameter nullable, and guard against null like this:

@BindingAdapter("imageUrl")
fun loadImage(view: RoundedImageView, url: String?) {
    if (!url.isNullOrEmpty()) {
        .....
    }
}

Solution 2

BindingAdapter methods should be static, so marking it @JvmStatic would help in this case.

But that will generate 'compile time error' that "methods can't be static inside class" and so it should be moved to companion object or named objects.

In your case, you're having method in class member level so moving it to companion object will help. So for MyItemViewModel.kt make companion object and move method there like below :

class MyItemViewModel{
    //Some code
    companion object {

        @JvmStatic
        @BindingAdapter("imageUrl")
        fun loadImage(view: RoundedImageView, url: String) { // This methods should not have any return type, = declaration would make it return that object declaration.
            Glide.with(view.context).load(url).into(view)
        }
    }
    //Some other code
}

Note: Also remove method declaration with =. Binding methods should have return type Unit.


Edit: One can also use method Glide.with(view) as @hmac suggested in comment, but ...

Things to consider before using this Glide.with(view):

  1. Your view should be attached before using it from Activity/Fragment. Best usecase for this method is Custom View/ViewGroup.

  2. Consider layout hierarchy before using this method as too many nested/large hierarchy layouts are discouraged to use that method. It becomes inefficient for such layouts.

  3. Also note that, if view is inside non-support fragment class or context is of non-support fragment than that can produce noisy log as documentation indicates, first migrate to support library (Now considered as AndroidX) instead before using this method!

Solution 3

This work fine for me

             <ImageView
                    android:layout_width="0dp"
                    android:layout_height="100dp"
                    android:layout_margin="10dp"
                    android:layout_gravity="center"
                    bind:image="@{subcategory.image}"
                    bind:placeholder="@{@drawable/no_imge}"
                    android:layout_weight="1" />




  @BindingAdapter("image","placeholder")
    fun setImage(image: ImageView, url: String?, placeHolder: Drawable) {

        if (!imageUrl.isNullOrEmpty()){

          Glide.with(image.context).load(url).centerCrop()
       .placeholder(R.drawable.no_imge)
                    .into(image)
        }
        else{
            image.setImageDrawable(placeHolder)
        }


    }

Solution 4

It would be more convenient to create a binding adapter which accepts multiple optional attributes so you can customize the loading request. Here's an example of such adapter.

@BindingAdapter(
  "srcUrl",
  "circleCrop",
  "placeholder",
  requireAll = false // make the attributes optional
)
fun ImageView.bindSrcUrl(
  url: String,
  circleCrop: Boolean = false,
  placeholder: Drawable?,
) = Glide.with(this).load(url).let { request ->

  if (circleCrop) {
    request.circleCrop()
  }

  if (placeholder != null) {
    request.placeholder(placeholder)
  }

  request.into(this)
}

And you can use it like this:

<ImageView
  ...
  app:srcUrl="@{someUrl}"
  app:placeholder="@{@drawable/ic_placeholder}"
  app:circleCrop="@{true}" />

You can also find an example in sources of the Owl - an official Android sample app on GitHub. See BindingAdapters.kt.

Solution 5

@JvmStatic
@BindingAdapter("glide")
fun glide(view: ShapeableImageView, url: String?) {
   if (!url.isNullOrEmpty()) {
      Glide.with(view).load(url).into(view)
   }
}
Share:
13,230
Hasan Kucuk
Author by

Hasan Kucuk

Android Developer | Blogger In love with Android &amp; Kotlin.

Updated on June 13, 2022

Comments

  • Hasan Kucuk
    Hasan Kucuk about 2 years

    I am trying to load image with databinding. But I never got over it. Where's my problem? Below is my code and layout construction.

    MyItemViewModel.kt

      @BindingAdapter("imageUrl")
        fun loadImage(view: RoundedImageView, url: String) = Glide.with(view.context).load(url).into(view)
    

    layout.xml

    <data>
    
        <variable
                name="viewModel"
                type="com.myapp.app.ui.activity.albumlist.AlbumItemViewModel"/>
    </data>
    
      <com.makeramen.roundedimageview.RoundedImageView
                    android:layout_width="60dp"
                    android:id="@+id/ivRoundedAlbum"
                    android:layout_marginStart="@dimen/unit_20_dp"
                    app:riv_corner_radius="8dp"
                    app:imageUrl="@{viewModel.data.cover}"
                    android:layout_height="60dp"/>
    
  • yash786
    yash786 almost 5 years
    To get imageurl at runtime we have to mentioned the path of the class where the url object is stored
  • Hasan Kucuk
    Hasan Kucuk almost 5 years
    What class should bindinAdapter be in exactly? Model.kt, AlbumItemViewModel.kt, AlbumViewModel.kt, AlbumAdapter.kt?
  • GOVIND DIXIT
    GOVIND DIXIT almost 5 years
    BindingAdapter should be in model class
  • Hasan Kucuk
    Hasan Kucuk almost 5 years
    : Required DataBindingComponent is null in class RowAlbumListBindingImpl. A BindingAdapter in com.myapp.app.model.AlbumList.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.
  • GOVIND DIXIT
    GOVIND DIXIT almost 5 years
    Yes the bindingAdapter method should be static as already mentioned.
  • IgorGanapolsky
    IgorGanapolsky over 4 years
    Where is the documentation in Glide that dictates BindingAdapter methods should be static?
  • hmac
    hmac about 4 years
    I think using Glide.with(view) is preferable, if you check the code and documentation this will respect the lifecycle of the Fragment (or Activity) that the view is shown in. with(context) "will only have application level options applied and will not be started or stopped based on lifecycle events...is appropriate for resources that will be used outside of the normal fragment or activity lifecycle"
  • Sathish Gadde
    Sathish Gadde over 3 years
    which namespace need to add for bind:
  • Amr
    Amr about 3 years
    @SathishGadde, write app instead of bind