Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inflate method using DataBindingComponent

I see this error while updating a textview once the image has been successfully rendered by Glide.

Fatal Exception: java.lang.IllegalStateException: Required DataBindingComponent is null in class CustomBinding. A BindingAdapter in CustomViewModel 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.

@BindingAdapter(value = { "android:src", "placeHolder" }, requireAll = false) 
public void setUrl(ImageView imageView, String url, Drawable placeHolder) {
          Glide.with(imageView.getContext())
              .load(url)
              .placeholder(placeHolder)
              .centerCrop()
              .listener(new Listener<String, Drawable>() {
                @Override
                public boolean onException() {
                  viewmodel.setTextVisible(true);// ERROR!
                  return false;
                }

                @Override public boolean onResourceReady() {
                  viewmodel.setTextVisible(false); // ERROR!
                  return false;
                }
              })
              .into(imageView);
        }

public void setTextVisible(boolean visibility) {
    textVisibility = visibility;
    notifyPropertyChanged(BR.textVisibility);
}

    @Bindable 
    public boolean getTextVisible() {
      return textVisibility; 
    }

This is how i initialise the viewmodel and bind the data inside the fragment:

CustomBinding binding =
        DataBindingUtil.inflate(inflater, R.layout.custom, container, 
false);

    CustomViewModel viewModel = new CustomViewModel(data, context);
    binding.setHandlers(new CustomHandlers(context));
    binding.setData(viewModel);

I cant find a way to actually implement this within a viewmodel. Thanks in advance for the help.

like image 834
user3133966 Avatar asked Aug 29 '17 07:08

user3133966


2 Answers

Was facing the same issue, got resolved by adding @JvmStatic annotation to the method and it works.

it should be in the form

@BindingAdapter("app:someAttribute")

@JvmStatic

example

class TestBindingHelper {

    companion object{

        @BindingAdapter("app:serviceOptions")
        @JvmStatic
        fun setServiceOptions(recyclerView: RecyclerView, listOfData: List<String>?) {
             //do something funny
        }

    }
}
like image 107
vikas kumar Avatar answered Oct 16 '22 14:10

vikas kumar


Your error tells you that the adapter you created is not static, but it has to be.
I am not quite sure that it is a good attempt to change the view model directly from the binding adapter.
Consider each binding adapter as a stand-alone static method, which is located in a separate class (say BindingUtills) and it can do staff with the parameters you pass to it.
In your example, It's not clear how do you pass the URL itself (I guess not through the android:src).
In this example adapter deals with the ImageView, image url and error drawable:

/**
 * Loads image from url and sets it into the Image View
 * with error drawable (set into imageview if failed to load the image)
 *
 * @param imageView       {@link ImageView}
 * @param url             image url
 * @param errorDrawable   Drawable to set in case of load error.
 */
@BindingAdapter({"bind:imageUrlRound", "bind:imageError"})
public static void loadRoundImage(ImageView imageView, String url, Drawable errorDrawable) {
    Glide.with(imageView.getContext())
            .load(url)
            .asBitmap()
            .error(errorDrawable)
            .centerCrop()
            .animate(R.anim.fade_in)
            .into(new BitmapImageViewTarget(imageView) {
                @Override
                protected void setResource(Bitmap resource) {
                    RoundedBitmapDrawable circularBitmapDrawable =
                            RoundedBitmapDrawableFactory.create(imageView.getContext().getResources(), resource);
                    circularBitmapDrawable.setCircular(true);
                    imageView.setImageDrawable(circularBitmapDrawable);
                }
            });
}

What in layout looks like:

<ImageView
...
app:imageUrlRound="@{yourViewModel.image}"
app:imageError="@{@drawable/ic_error}" />

I am not sure that this is a good practice, but you may try to add the view model as another binding attribute as well as a parameter of the adapter and change it's param in the glide's callback.
P.S. Also simplify your view model (create a mapper to make in handy) to contain only the parameters you want to show in the layout (i.e. Strings ints etc) IMHO it's strange to pass context there...

like image 26
Leonid Ustenko Avatar answered Oct 16 '22 15:10

Leonid Ustenko