Android数据绑定使用“&&”逻辑运算符

182

我正尝试在使用Android DataBinding时,在xml中使用"&&"运算符,

android:visibility="@{(bean.currentSpaceId == bean.selectedSpaceId && bean.currentSpaceId > 0)? View.VISIBLE: View.GONE}"

但是我得到了编译错误:

Error:Execution failed for task ':app:dataBindingProcessLayoutsDevDebug'. org.xml.sax.SAXParseException; systemId: file:/Users/path/app/build/intermediates/res/merged/dev/debug/layout/fragment_space.xml; lineNumber: 106; columnNumber: 89; The entity name must immediately follow the '&' in the entity reference.

并且在Android Studio中以红色突出显示"unescaped & or non terminated character"。

那么我应该如何解决这个问题?

编辑: 找到了答案,这些字符需要转义:

'&' --> '&'

'<' --> '&lt;'

'>' --> '&gt;'

1
我注意到在布局XML文件中可以使用“>”和“<”符号。 - Hong
5个回答

311

&& 应该被渲染为 &amp;&amp;

官方的 数据绑定指南 中有使用这些 XML 实体的比较运算符示例,例如

android:visibility="@{age &lt; 13 ? View.GONE : View.VISIBLE}"

编辑

我在回答中提到的示例表达式已经从英文版文档中消失,因为这个回答是写在一段时间之前的。它们仍然存在于一些过时的非英语版本的文档中,比如西班牙语版本。

不管怎样,原始答案仍然有效,因为在XML中使用XML实体是标准的XML用法,与Android本身无关。


14
不要在绑定表达式中使用领域逻辑,你需要使用展示器/控制器来完成这一点。 - artkoenig
4
如果您需要在用户界面中隐藏/显示某些控件,该怎么办?我使用数据绑定库来避免编写UI代码。 - Krusty
3
在你的Presenter中实现一个方法isMyControlVisible(),使用你的领域逻辑来返回true或false。将其绑定到相应的位置。 - artkoenig
2
我认为,如果你有太多的布尔变量,这个解决方案是可行的。否则,你的代码将有大量的ObservableBoolean.set。 - Lester
@artkoenig 那么你就必须在引用布局的任何地方维护这些额外的布尔值。这会导致错误的源头。 - Ali Kazi

68

HTML实体列表

在XML中无法使用&或其他一些HTML实体,因此您必须使用转义字符。

android:text="@{(1==1 &amp;&amp; 2>0) ? `true` : `false`}"

在Android中经常使用的HTML字符实体:

+--------+----------------------------+--+--+--+
| Symbol | Equivalent HTML Entity     |  |  |  |
+--------+----------------------------+--+--+--+
| >      | &gt;                       |  |  |  |
+--------+----------------------------+--+--+--+
| <      | &lt;                       |  |  |  |
+--------+----------------------------+--+--+--+
| "      | &quot;, &ldquo; or &rdquo; |  |  |  |
+--------+----------------------------+--+--+--+
| '      | &apos;, &lsquo; or &rsquo; |  |  |  |
+--------+----------------------------+--+--+--+
| }      | &#125;                     |  |  |  |
+--------+----------------------------+--+--+--+
| &      | &amp;                      |  |  |  |
+--------+----------------------------+--+--+--+
| space  | &#160;                     |  |  |  |
+--------+----------------------------+--+--+--+

这里是HTML实体的完整列表。


22

在布局标记中使用&符号是一个很差的解决方案。更好的方法是在(视图)模型对象上创建一个方法:

转义&&在布局标记中是一个非常糟糕的解决方案。最好的方法是在(视图)模型对象上创建一个方法:

android:visibility="@{user.adult ? View.VISIBLE : View.GONE}"

public boolean isAdult() {
    return age >= 18;
}

5
虽然这是一个不错的解决方案,但遗憾的是当变量值改变时(notifyPropertyChanged),它不会被调用,因此可见性不会更新。 - Bernd Kampl
3
@BerndKampl 使用ObservableBoolean isAdult - S1ngoooor
这样不行,它只会被调用一次! - CodingTT
@BerndKampl 如何使用它,它仍会被调用一次。 - CodingTT
@CodingTT,请看一下我的答案,你需要在某个地方调用notifyPropertyChanged来更新它。 - Bernd Kampl
@BerndKampl 他们建议创建一个 ObservableBoolean,当年龄值更新时,它的值也会被更新。 - k2col

5
我能想到的最好的解决方案是引入一个新的Bindable方法。

之前:

item_recyclerview.xml

<EditText
...
android:enabled="@{myViewModel.myDataModelClass.lastAddedItem &amp;&amp; !myViewModel.myDataModelClass.editTextDisabled}"
/>

MyDataModelClass: (它被保存在我的视图模型中)

...
private boolean lastAddedItem;
private boolean editTextDisabled;
...
@Bindable
public boolean isLastAddedItem() {
    return lastAddedItem;
}
public void setLastAddedItem(boolean lastAddedItem) {
    this.lastAddeditem = lastAddedItem;
    notifyPropertyChanged(BR.lastAddedItem);
}
@Bindable
public boolean isEditTextDisabled() {
    return editTextDisabled;
}
public void setEditTextDisabled(boolean editTextDisabled) {
    this.editTextDisabled = editTextDisabled;
    notifyPropertyChanged(BR.editTextDisabled);
}

After:

item_recyclerview.xml:

<EditText
...
android:enabled="@{myViewModel.myDataModelClass.enableEditing}"
/>

“MyDataModelClass”:(它被保存在我的视图模型中)
...
private boolean lastAddedItem;
private boolean editTextDisabled;
...
@Bindable
public boolean isLastAddedItem() {
    return lastAddedItem;
}
public void setLastAddedItem(boolean lastAddedItem) {
    this.lastAddeditem = lastAddedItem;
    notifyPropertyChanged(BR.lastAddedItem);
    notifyPropertyChanged(BR.isEnableEditing);
}
@Bindable
public boolean isEditTextDisabled() {
    return editTextDisabled;
}
public void setEditTextDisabled(boolean editTextDisabled) {
    this.editTextDisabled = editTextDisabled;
    notifyPropertyChanged(BR.editTextDisabled);
    notifyPropertyChanged(BR.isEnableEditing);
}
@Bindable
public boolean isEnableEditing() {
    return isLastAddedItem() && !isEditTextDisabled();
}

那段代码正在使用BaseObservable类,BR是生成的绑定类。请参阅此文章以获得更详细的解释:https://medium.com/@jencisov/androids-data-binding-s-baseobservable-class-and-bindable-annotation-in-kotlin-1a5c6682a3c1 - Bernd Kampl

0
尝试在XML中使用“compareTo”方法,例如:
android:visibility=${viewModel.intValue.compareTo(0) == -1 ? View.GONE : View.VISIBLE}"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接