Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Spinner two-way binding with @InverseBindingAdapter / AttrChanged doesn't work

I've been trying for a while to set up a two-way binding on a Spinner.

There are many example of this on the web and here on stack overflow but none of them works for me.

It's just a country spinner, I've defined a country adapter for it with this methods:

@InverseBindingAdapter(attribute = "selectedCountry", event = "selectedCountryAttrChanged")
public static String bindCountryInverseAdapter(AppCompatSpinner pAppCompatSpinner) {
    Object selectedItem = pAppCompatSpinner.getSelectedItem();
    SpinnerAdapter adapter = pAppCompatSpinner.getAdapter();
    if (adapter instanceof CountrySpinnerAdapter) {
        return (String) selectedItem;
    }
    throw new UnsupportedOperationException("The adapter must be a CountrySpinnerAdapter");
}

@BindingAdapter(value = "selectedCountryAttrChanged", requireAll = false)
public static void bindCountryChanged(AppCompatSpinner pAppCompatSpinner, final InverseBindingListener newTextAttrChanged) {
    AdapterView.OnItemSelectedListener listener = new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            newTextAttrChanged.onChange();
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {
            newTextAttrChanged.onChange();
        }
    };
    pAppCompatSpinner.setOnItemSelectedListener(listener);

}

@BindingAdapter("selectedCountry")
public static void bindCountryValue(AppCompatSpinner pAppCompatSpinner, String newSelectedValue) {
    SpinnerAdapter adapter = pAppCompatSpinner.getAdapter();
    if (adapter instanceof CountrySpinnerAdapter) {
        ((CountrySpinnerAdapter) adapter).bindSelectedValue(pAppCompatSpinner, newSelectedValue);
        return;
    }
    throw new UnsupportedOperationException("The adapter must be a CountrySpinnerAdapter");
}

the bindCountryChanged method is never called.

I've also tried this variant (following other examples):

@BindingAdapter(value = {"selectedCountry", "selectedCountryAttrChanged"}, requireAll = false)
public static void bindCountryValueChanged(AppCompatSpinner pAppCompatSpinner, String newSelectedValue, final InverseBindingListener newTextAttrChanged) {
    AdapterView.OnItemSelectedListener listener = new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            newTextAttrChanged.onChange();
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {
            newTextAttrChanged.onChange();
        }
    };
    pAppCompatSpinner.setOnItemSelectedListener(listener);

}

This is called but newTextAttrChanged is always null.

The layout, binding part:

<data>
    <variable
        name="customer"
        type="my.package.CustomerBinding" />
</data>

And the widget:

<android.support.v7.widget.AppCompatSpinner
    android:id="@+id/editCountry"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_weight="1"
    android:spinnerMode="dropdown"
    app:adapter="@{customer.countrySpinnerAdapter}"
    app:selectedCountry="@{customer.country}" />

country id just an ObservableField<String> and countrySpinnerAdapter is a BaseAdapter for the list of countries.

Android gradle plugin:

classpath 'com.android.tools.build:gradle:2.2.1'

Tools versions:

buildToolsVersion "24.0.2"

And of course data binding is enabled:

dataBinding {
    enabled = true
}

Why newTextAttrChanged is always null / the BindingAdapter is never calld? What am I doing wrong?

like image 985
Daniele Segato Avatar asked Dec 15 '22 03:12

Daniele Segato


1 Answers

You are missing the = in the binding expression to notify the system that you would like to use this binding as a two-way binding.

app:selectedCountry="@{customer.country}"

should be

app:selectedCountry="@={customer.country}"
like image 192
yennsarah Avatar answered Apr 25 '23 12:04

yennsarah