Android Data Binding编译报错:Spinner的selectedValue属性无对应getter
问题描述
我参考了一份Spinner数据绑定的实现方案,但代码无法编译,报错信息如下:
Found data binding errors. ****/ data binding error ****msg:Cannot find the getter for attribute 'selectedValue' with value type java.lang.String on android.widget.Spinner. file:D:\Khemraj_AndroidStudioWorkspace_\amelioFinal\app\src\main\res\layout\activity_cart.xml loc:167:24 - 175:33 ****\ data binding error ****
相关代码片段
ViewModel 代码
public class ViewModel { private String text; public String getText() { return text; } public void setText(String text) { this.text = text; } }
XML布局变量定义
<variable name="viewModel" type="com.amelio.model.ViewModel"/>
Spinner布局代码
<android.support.v7.widget.AppCompatSpinner android:layout_width="wrap_content" android:layout_height="wrap_content" android:entries="@array/days" bind:selectedValue="@={viewModel.text}"/>
绑定工具类代码
public class SpinnerBindingUtil { @BindingAdapter(value = {"selectedValue", "selectedValueAttrChanged"}, requireAll = false) public static void bindSpinnerData(AppCompatSpinner pAppCompatSpinner, String newSelectedValue, final InverseBindingListener newTextAttrChanged) { pAppCompatSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { newTextAttrChanged.onChange(); } @Override public void onNothingSelected(AdapterView<?> parent) { } }); if (newSelectedValue != null) { int pos = ((ArrayAdapter<String>) pAppCompatSpinner.getAdapter()).getPosition(newSelectedValue); pAppCompatSpinner.setSelection(pos, true); } } @InverseBindingAdapter(attribute = "selectedValue", event = "selectedValueAttrChanged") public static String captureSelectedValue(AppCompatSpinner pAppCompatSpinner) { return (String) pAppCompatSpinner.getSelectedItem(); } }
问题根源与解决步骤
这个编译错误的核心是数据绑定框架没正确识别你自定义的selectedValue属性,或者说没有关联到你的SpinnerBindingUtil工具类。下面是具体的修复方案:
声明正确的命名空间
在布局的根标签里,必须添加bind(或app)命名空间,指向数据绑定的schemas,否则框架无法识别自定义的绑定属性:<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:bind="http://schemas.android.com/apk/res-auto" <!-- 关键:添加这个命名空间 --> android:layout_width="match_parent" android:layout_height="match_parent">如果你习惯用
app:前缀,把布局里的bind:selectedValue改成app:selectedValue即可,保持前缀一致就行。确保工具类被数据绑定识别
在布局的<data>标签中,导入你的SpinnerBindingUtil类,让数据绑定框架能找到对应的绑定方法:<data> <variable name="viewModel" type="com.amelio.model.ViewModel"/> <import type="com.amelio.util.SpinnerBindingUtil"/> <!-- 替换成你的工具类实际包路径 --> </data>注意:工具类必须是
public访问权限,否则框架无法访问。优化绑定方法逻辑(避免循环与重复监听)
你当前的bindSpinnerData方法每次调用都会设置新的OnItemSelectedListener,容易导致重复监听和数据循环更新的问题。可以优化一下:public static void bindSpinnerData(AppCompatSpinner spinner, String newSelectedValue, final InverseBindingListener listener) { // 仅在未设置监听器时添加,避免重复绑定 if (spinner.getOnItemSelectedListener() == null) { spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { listener.onChange(); } @Override public void onNothingSelected(AdapterView<?> parent) { listener.onChange(); // 空选择时也同步数据 } }); } // 仅当选中值不同时才更新,避免无限循环 if (newSelectedValue != null && !newSelectedValue.equals(spinner.getSelectedItem())) { int pos = ((ArrayAdapter<String>) spinner.getAdapter()).getPosition(newSelectedValue); spinner.setSelection(pos, false); // false表示不触发onItemSelected,避免循环 } }验证数组资源类型
确保@array/days是字符串数组,在res/values/strings.xml中定义如下:<string-array name="days"> <item>Monday</item> <item>Tuesday</item> <item>Wednesday</item> </string-array>这样才能保证
ArrayAdapter<String>的类型转换安全,避免运行时崩溃。
完成以上修改后,重新编译项目,应该就能解决这个数据绑定的编译错误了。
内容的提问来源于stack exchange,提问作者Khemraj Sharma

