I am quite new in Android Data Binding
. I am following this tutorial: Data Binding Library.
I am trying to do an adapter that receive multiple parameters. This is my code:
XML
<ImageView
android:layout_width="@dimen/place_holder_size"
android:layout_height="@dimen/place_holder_size"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_centerVertical="true"
app:url="@{image.imageUrl}"
app:size="@{@dimen/place_holder_size}"
/>
BINDING ADAPTER CLASS
public class ViewBindingAdapters extends BaseObservable {
@BindingAdapter({"bind:url", "bind:size"})
public static void loadImage(ImageView imageView, String url, int size) {
if (!Strings.isNullOrEmpty(url)) {
Picasso.with(imageView.getContext()).load(url).resize(size, size).centerCrop().into(imageView);
}
}
....
}
But I am getting this error:
java.lang.RuntimeException: Found data binding errors. ****/ data binding error ****msg:Cannot find the setter for attribute 'app:url' with parameter type java.lang.String on android.widget.ImageView. file:... li_image_item.xml loc:30:27 - 30:40 ****\ data binding error ****
Does anybody know why??
Thanks in advance!
Using data binding can lead to faster development times, faster execution times and more readable and maintained code. Android data binding generates binding classes at compile time for layouts.
Binding adapters are responsible for making the appropriate framework calls to set values. One example is setting a property value like calling the setText() method. Another example is setting an event listener like calling the setOnClickListener() method.
Two-way Data Binding is a technique of binding your objects to your XML layouts so that the layout can send data to your binding object. This is compared to a “traditional” or “one-way” Data Binding setup, where data would only move from your binding object to the layout.
Data binding in Android Updating the views from the data source is a simple one-way binding. In that case, you'll only access data from the data source and update the layout. Two-way data binding is nothing but updating the data source if there are any changes in the layout and vice versa.
Problem is @dimen/place_holder_size
, it returns float
while you are catching it as int
change you BindingAdapter
method to this
@BindingAdapter({"bind:url", "bind:size"})
public static void loadImage(ImageView imageView, String url, float size) {
}
you can refer this
What I did wrong is the order of the arguments in the function. You can add multiple attributes in Binding Adapter, but they should match the arguments with the same sequence defined in the method.
Here is my code snippet for Kotlin
@BindingAdapter(value = ["bind:brand", "bind:model", "bind:age"], requireAll = false)
@JvmStatic
fun bindProductDetails(linearLayout: LinearLayout, brand: String?, model: String?, age: String?) {
if (brand != null && !brand.isEmpty()) {
//code
//code
}
}
try this
@BindingAdapter(value={"url", "size"}, requireAll=false)
public static void loadImage(ImageView imageView, String url, int size) {
if (!Strings.isNullOrEmpty(url)) {
Picasso.with(imageView.getContext()).load(url).resize(size, size).centerCrop().into(imageView);
}
}
You don't need to create prefix bind:
, just use this.
@BindingAdapter({"url", "size"})
public static void loadImage(ImageView imageView, String url, float size) {
}
In xml use any prefix like app:
app:url="@{image.imageUrl}"
Apart from the example provided above by @Kishan Solanki, And with changes happening in the Data Binding library, all you need is to declare them with comma separated values. Example
@BindingAdapter("loadImageFrom", "widthDp")
fun loadImages(imageView: ImageView, url: String?, widthDp: Int) {
url?.let {
val height = (widthDp / 3) * 4
val fullUrl = getImagePosterUrl(url)
Picasso.get().load(fullUrl).resize(widthDp.px, height.px).into(imageView)
}
}
Bu the most important thing to remember is that you provide the data to the adapter attributes, in the DataBinding format.
example to provide Int as parameter in XML you have to write
app:widthDp="@{120}"
which is
app:your_attribute="@{your_data}"
P. S. - Oh and one more thing, widthDp**.px** is an extension function which converts Int
of a dp value to relevant pixels value based on screen density. So don't get confused.
See https://developer.android.com/topic/libraries/data-binding/binding-adapters.
@BindingAdapter("imageUrl", "placeholder", requireAll = false)
fun ImageView.setImageUrl(url: String?, placeHolder: Drawable?) {
if (url == null) {
setImageDrawable(placeholder)
} else {
MyImageLoader.loadInto(this, url, placeholder)
}
}
Note that BindingAdapter
attributes and setImageUrl
parameters may have different names. But they should go in the same order. If some of these attributes are defined in XML (in this example it is ImageView
), this method will be called.
<ImageView
app:imageUrl="@{venue.imageUrl}"
app:placeholder="@{@drawable/venueError}" />
Attributes should have the same types as defined in the method. You can also use listeners. Instead of Kotlin lambdas use interfaces.
This class should be put in the same module with XML. Otherwise you will get an error like AAPT: error: attribute imageUrl (aka com.example.imageUrl) not found.
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With