package com.airbnb.epoxy; import android.databinding.DataBindingUtil; import android.databinding.ViewDataBinding; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.airbnb.epoxy.DataBindingEpoxyModel.DataBindingHolder; import java.util.List; /** * A version of {@link com.airbnb.epoxy.EpoxyModel} that can be used with databinding. The layout * resource used with this model must be a databinding layout. This class will create the * databinding object from the layout and call the {@link #setDataBindingVariables} methods when the * view needs binding to the model. * <p> * The easiest way to use this model is to have Epoxy generate a model to do all the binding work * for you. To do this, create an abstract subclass of this model, annotate it with {@link * EpoxyModelClass}, and pass your layout resource as the layout param. (You must pass the layout * this way instead of implementing {@link #getDefaultLayout()}). * <p> * Then, make a field to represent each of the data variables in your layout and annotate each one * with {@link EpoxyAttribute}. The name of each field must match the name of the variable in the * layout exactly. * <p> * Epoxy will generate a subclass of your model at compile time that implements {@link * #setDataBindingVariables(ViewDataBinding)} and {@link #setDataBindingVariables(ViewDataBinding, * EpoxyModel)} for you. This will do all binding for you, and also only bind variables that change * if you update your model (Note: The change optimization only works when used with {@link * EpoxyController}). */ public abstract class DataBindingEpoxyModel extends EpoxyModelWithHolder<DataBindingHolder> { @Override View buildView(ViewGroup parent) { LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext()); ViewDataBinding binding = DataBindingUtil.inflate(layoutInflater, getViewType(), parent, false); View view = binding.getRoot(); view.setTag(binding); return view; } @Override public void bind(DataBindingHolder holder) { setDataBindingVariables(holder.dataBinding); holder.dataBinding.executePendingBindings(); } @Override public void bind(DataBindingHolder holder, EpoxyModel<?> previouslyBoundModel) { setDataBindingVariables(holder.dataBinding, previouslyBoundModel); holder.dataBinding.executePendingBindings(); } @Override public void bind(DataBindingHolder holder, List<Object> payloads) { setDataBindingVariables(holder.dataBinding, payloads); holder.dataBinding.executePendingBindings(); } /** * This is called when the model is bound to a view, and the view's variables should be updated * with the model's data. {@link ViewDataBinding#executePendingBindings()} is called for you after * this method is run. * <p> * If you leave your class abstract and have a model generated for you via annotations this will * be implemented for you. However, you may choose to implement this manually if you like. */ protected abstract void setDataBindingVariables(ViewDataBinding binding); /** * Similar to {@link #setDataBindingVariables(ViewDataBinding)}, but this method only binds * variables that have changed. The changed model comes from {@link #bind(DataBindingHolder, * EpoxyModel)}. This will only be called if the model is used in an {@link EpoxyController} * <p> * If you leave your class abstract and have a model generated for you via annotations this will * be implemented for you. However, you may choose to implement this manually if you like. */ protected void setDataBindingVariables(ViewDataBinding dataBinding, EpoxyModel<?> previouslyBoundModel) { setDataBindingVariables(dataBinding); } protected void setDataBindingVariables(ViewDataBinding dataBinding, List<Object> payloads) { setDataBindingVariables(dataBinding); } @Override public void unbind(DataBindingHolder holder) { holder.dataBinding.unbind(); } @Override protected final DataBindingHolder createNewHolder() { return new DataBindingHolder(); } public static class DataBindingHolder extends EpoxyHolder { private ViewDataBinding dataBinding; public ViewDataBinding getDataBinding() { return dataBinding; } @Override protected void bindView(View itemView) { dataBinding = (ViewDataBinding) itemView.getTag(); } } }