I have been reading articles about binding adapter in Android, but I don't seem to understand it. When is a binding adapter used? Can someone explain it with a simple example?
An article I read had a binding adapter in the Main Activity. The binding Adapter had a parameter "toastMessage", and apparently, the method annotated with this binding adapter was said to be called whenever the "toastMessage" (which was an attribute in viewModel class) changed.
I don't understand why we need to do this.
An explanation with a simple example would help a lot.
Thanks!
The Data Binding Library is a support library that allows you to bind UI components in your layouts to data sources in your app using a declarative format rather than programmatically.
View binding allows a developer to incorporate significant interaction in an application. This concept seeks to eliminate the findViewById keyword. Removing such boilerplate code allows developers to be more productive. A binding class is usually generated for each layout file when using view binding.
Binding Adapters are used to have custom setters to some property of your views. The most common use case I can think of is setting an image to an ImageView
, where loading of image is mostly done off the UI thread.
Most of us have our preferred image loading library to load images. For every image you would want to load you would write code to load the url from remote (or local) and set it to our image view. You could of course have some utility method once you see this boilerplate in every place you have an image view.
Binding adapters makes this a little more simpler. You set the attribute in XML and data binding library will look for the binding adapter to set that property to your view. Since the data is an observable changes will be triggered to the view whenever the data changes.
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:imageUrl="@{data.imageUrl}"/>
@BindingAdapter("imageUrl")
public static void setImageUrl(ImageView imageView, String url) {
if (url == null) {
imageView.setImageDrawable(null);
} else {
Picasso.get().load(url).into(imageView); // replace with your fav image loading lib
}
}
The doc provides several such examples where you would want to use this. This article by George Mount also explains it very clearly where and why you may want to use this if you are using data binding.
Binding adapters are responsible for making the appropriate framework calls to set values.
When you're using data binding
into your application, setting values into your views
is a normal thing. Like below example:
<ProgressBar
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:visibility="@{viewmodel.loadingData?View.VISIBLE:View.GONE}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
But some times you want to do something special in your setting methods. For example, you have a RecyclerView
in your XML
and you want to define its adapter, You can do it by defining it via a bindingAdapter
in your code for it.
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_main_articles"
app:adapter="@{viewmodel.articles}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_width="0dp"
android:layout_height="0dp"/>
There are mostly two usages of binding adapters:
1- For RecyclerView:
@JvmStatic
@BindingAdapter("app:adapter")
fun <T> setItems(recyclerView: RecyclerView, items: List<T>?) {
Log.d(TAG, "articles:[$items]")
if (recyclerView.adapter is HomeAdapter) {
if (items != null) {
(recyclerView.adapter as HomeAdapter).swapData(items)
}
}
}
2- For loading images into your ImageView
(s)
@JvmStatic
@BindingAdapter("app:loadImage")
fun setImageResource(view: ImageView, imageUrl: String?) {
val context = view.context
val options = RequestOptions()
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
imageUrl?.let {
Glide.with(context)
.setDefaultRequestOptions(options)
.load(imageUrl)
.transition(DrawableTransitionOptions.withCrossFade(1000))
.into(view)
}
}
More info : link
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