Say for instance I have the following variable in my data bound XML.
<layout ...>
<data>
<variable name="listener" type="com.xyz.Listener" />
<!-- and other variables -->
</data>
...
</layout>
I use this variable in every single one of my data-bound layouts, and I need to access it in almost every single one of my @BindingAdapter. For instance, my binding adapters mostly look like this.
@BindingAdapter("board")
fun setBoard(view: TextView, board: Board) {
view.setText(board.name)
view.setOnClickListener {
listener.onBoardClicked(board)
}
}
@BindingAdapter("topic")
fun setTopic(view: TextView, topic: Topic) {
view.setText(topic.name)
view.setOnClickListener {
listener.onTopicClicked(topic)
}
}
// and a few others like that
and I use them like this
<TextView ... app:board="@{board}" ... />
<TextView ... app:topic="@{topic}" ... />
What I need here is a way to access that listener variable declared in the data block to all of my binding adapters. Is there a way to do that without manually passing it as a second variable every single time?
// I know I can do this - looking for an alternative
@BindingAdapter({"board", "listener"})
fun setBoard(view: TextView, board: Board, listener: Listener) {
view.setText(board.name)
view.setOnClickListener {
listener.onBoardClicked(board)
}
}
I am using Kotlin here, but a solution in Java works just fine for me as well.
After doing some more research, I've just discovered the DataBindingComponent interface and it solves precisely the problem I was having. Apparently, if you make your binding adapters instance methods rather than static, the compiler will take the class you declared it in, and add it as a property of DataBindingComponent. So I made my binding adapters instance methods, and injected the variable I wanted via the constructor.
class Binding(val listener: Listener) {
@BindingAdapter("board")
fun setBoard(view: TextView, board: Board) {
view.setText(board.name)
view.setOnClickListener {
listener.onBoardClicked(board)
}
}
@BindingAdapter("topic")
fun setTopic(view: TextView, topic: Topic) {
view.setText(topic.name)
view.setOnClickListener {
listener.onTopicClicked(topic)
}
}
}
After building, the compiler generated the following interface
package android.databinding;
public interface DataBindingComponent {
com.my.package.Binding getBinding();
}
I then completed the cycle by making the binding class extend this interface and return itself
class Binding(val listener: Listener) : DataBindingComponent {
override fun getBinding(): Binding {
return this
}
// all the other stuff
}
This allows me to pass it as an argument when inflating views, and as such I no longer have to even declare listener as an XML variable. I can just declare the Binding instance
val bindingComponent = Binding(object : Listener {
// implement listener methods here
})
and pass it when inflating the layout
// now I can use it in activities
DataBindingUtil.setContentView<MyActivityBinding>(
this, R.layout.my_activity, bindingComponent)
// ...or in fragments
DataBindingUtil.inflate<MyFragmentBinding>(
inflater, R.layout.my_fragment, parent, false)
// ...or any other place DataBindingUtil allows
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