-
Notifications
You must be signed in to change notification settings - Fork 727
Data Binding Support
Epoxy integrates with Android data binding to automatically generate EpoxyModels from databinding xml layouts.
To enable data binding support, add the epoxy databinding module as a dependency:
dependencies {
compile 'com.airbnb.android:epoxy-databinding:2.6.0' // (or latest Epoxy version)
}
Also make sure to enable Android data binding in your build.gradle
file.
android {
dataBinding {
enabled = true
}
}
Epoxy can generate an EpoxyModel for each of your data binding layouts.
Models are generated in the root package of your module. Each model will have a setter for each of the variables in the layout, and each variable will be bound when the model is bound.
The generated model name is created by camel casing the layout file name and appending BindingModel_
. The layouts must not specify a custom data binding class name or package via the class="com.example.CustomClassName"
override in the layout xml.
There are two ways to tell Epoxy which layouts you want models generated for:
Create a package-info.java
file in any package and annotate it with EpoxyDataBindingPattern
. Add your R class as an argument, as well as a prefix that all of your databinding layouts share.
Epoxy will attempt to generate a databinding model for every layout file that starts with the given prefix.
For example,
@EpoxyDataBindingPattern(rClass = R.class, layoutPrefix = "view_holder")
package com.example.package;
Your layouts would then be named like view_holder_list_item.xml
, which would lead to a ListItemBindingModel_
model class being generated.
Create a package-info.java
file in any package and annotate it with EpoxyDataBindingLayouts
. Then include your layout file names in the annotation.
For example,
@EpoxyDataBindingLayouts({R.layout.header_view})
package com.example.package;
Generally all data variables must implement equals and hashcode so Epoxy can detect when they change. Each variable is rebound individually when it changes. Read more about this under the Model Properties section.
For any variable that does not implement equals and hashcode Epoxy applies its Do Not Hash option by default. This default is generally helpful for click listeners, but there are some caveats to the behavior that should be understood to avoid bugs.
To disable this default you can set enableDoNotHash
in your EpoxyDataBindingLayouts
and EpoxyDataBindingPattern annotations
to false.
You may also subclass DataBindingEpoxyModel
directly if you want to handle binding manually, although this should rarely be needed.
You can create a simple model like this:
@EpoxyModelClass(layout = R.layout.model_button)
public abstract class ButtonModel extends DataBindingEpoxyModel {
@EpoxyAttribute @StringRes int textRes;
@EpoxyAttribute(DoNotHash) OnClickListener clickListener;
@Override
protected void setDataBindingVariables(ViewDataBinding binding) {
binding.setVariable(BR.textRes, textRes);
binding.setVariable(BR.clickListener, clickListener); }
}
The setDataBindingVariables
method will be called when the model is bound, giving you a chance to bind your data to the view. Alternatively you can leave the setDataBindingVariables
method unimplemented and Epoxy will include a default implementation for you that binds each EpoxyAttribute field to a variable of the same name.
This simplies the model to just:
@EpoxyModelClass(layout = R.layout.model_button)
public abstract class ButtonModel extends DataBindingEpoxyModel {
@EpoxyAttribute @StringRes int textRes;
@EpoxyAttribute(DoNotHash) OnClickListener clickListener;
}
In this case the generated implementation of setDataBindingVariables
would be exactly the same as implemented earlier. The generated code will also include a setDataBindingVariables
implementation that only updates a variable if it changed from the previously bound model.
For example:
@Override
protected void setDataBindingVariables(ViewDataBinding binding, EpoxyModel previousModel) {
ButtonModel_ that = (ButtonModel_) previousModel;
if (textRes != that.textRes) {
binding.setVariable(BR.textRes, textRes);
}
if ((clickListener == null) != (that.clickListener == null)) {
binding.setVariable(BR.clickListener, clickListener);
}
}