I need to understand how the Data Binding Library determine the order of execution for its BindingAdapters. If I have two BindingAdapters for a View and if the View has both the attributes corresponding to those BindingAdapters, how will it determine which adapter will be executed first? I ask because the order of execution matters in my case.
I have the following BindingAdapter/s:
public class SpinnerBindingAdapter {
@BindingAdapter(value = {"entries"})
public static void setEntries(Spinner spinner, List<? extends SpinnerItem> spinnerItems) {
for (int i = 0; i < spinnerItems.size(); i++) {
spinnerItems.get(i).setIndex(i);
}
ArrayAdapter<? extends SpinnerItem> adapter =
new ArrayAdapter<>(spinner.getContext(), R.layout.spinner_item, spinnerItems);
spinner.setAdapter(adapter);
}
@InverseBindingAdapter(attribute = "selectedItem", event = "selectedItemAttrChanged")
public static Object getSelectedItem(Spinner spinner) {
Object selectedItem = spinner.getSelectedItem();
return selectedItem;
}
@BindingAdapter(value = {"selectedItem"})
public static void setSelectedItem(Spinner spinner, SpinnerItem spinnerItem) {
if (spinner.getAdapter() == null) {
return;
}
// Other code omitted for simplicity
}
@BindingAdapter(value = {"selectedItemAttrChanged"}, requireAll = false)
public static void setOnItemSelectedListener(Spinner spinner, final InverseBindingListener selectedItemChange) {
if (selectedItemChange == null) {
spinner.setOnItemSelectedListener(null);
} else {
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
selectedItemChange.onChange();
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
}
}
And here is how I populate the Spinner and set the selection:
<Spinner
android:id="@+id/spinner_system_activity_edit_tracker_unit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="fill_horizontal"
app:entries="@{DatabaseModel.queryForAll()}"
app:selectedItem="@={object.selectedItem}"/>
DatabaseModel.queryForAll is a static method that queries the database and returns a list of objects which is then given to the BindingAdapter. The BindingAdapter takes this list, update each of its item with an index and set it as an adapter for the spinner.
For whatever reason, the "setSelectedItem" BindingAdapter always gets called first. This is undesirable, because I need the entries to be initialised first. If its not initialised first then spinner.getAdapter() will be null when setSelectedItem is first called. Which means that previous saved selection will not be restored.
To create a custom binding adapter, you need to create an extension function of the view that will use the adapter. Then, you add the @BindingAdapter annotation. You have to indicate the name of the view attribute that will execute this adapter as a parameter in the annotation.
implements Annotation. android.databinding.BindingAdapter. BindingAdapter is applied to methods that are used to manipulate how values with expressions are set to views.
A binding adapter is simply a static or instance method that is used to manipulate how some user defined attributes map data bound variables to views. Again, to elaborate on an example from the documentation, say we want to set the left padding on a view.
There is no guaranteed order of execution in Android Data Binding. Because of this, you should merge binding adapters that have reliance on multiple attributes. In your case, you need to merge the binding adapter for selectedItem and entries.
@BindingAdapter(value = {"selectedItem", "entries"}, requireAll = false)
public static void setSelectedItem(Spinner spinner, SpinnerItem spinnerItem,
List<? extends SpinnerItem> spinnerItems) {
// Set entries attribute when provided
if (spinnerItems != null) {
for (int i = 0; i < spinnerItems.size(); i++) {
spinnerItems.get(i).setIndex(i);
}
ArrayAdapter<? extends SpinnerItem> adapter =
new ArrayAdapter<>(spinner.getContext(), R.layout.spinner_item, spinnerItems);
spinner.setAdapter(adapter);
}
// set selectedItem attribute when provided
if (spinnerItem != null) {
if (spinner.getAdapter() == null) {
return;
}
// Other code omitted for simplicity
}
}
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