Data Binding允许通过写表达式来处理view分发的事件,e.g.onClick。事件属性名通常通过listener方法的名字管理,但存在个别例外。e.g.View.OnLongClickListener有个方法onLongClick(),这时事件的属性名是android:onLongClick。
有两种方法来处理事件
- 方法引用Method Reference
在表达式中,可以引用符合监听器中方法签名的方法。 - 监听器绑定Listener Bindings
使用lambda表达式,当事件发生时,对这些lambda表达式进行计算。
方法引用
官方说明:In your expressions, you can reference methods that conform to the signature of the listener method. When an expression evaluates to a method reference, Data Binding wraps the method reference and owner object in a listener, and sets that listener on the target view. If the expression evaluates to null, Data Binding does not create a listener and sets a null listener instead.
事件和处理方法可被直接绑定,这和android:onClick能被Activity中方法赋值类似。方法引用相比View#onClick属性的主要优点是表达式在编译时处理,如果方法不存在或者签名不对,你将会收到一个编译错误。
方法引用和监听器绑定之间的主要区别是前者在数据绑定时创建真正的监听器实现,而不是事件被触发时。如果你倾向与事件发生时计算表达式,请使用监听器绑定方法。
To assign an event to its handler, use a normal binding expression, with the value being the method name to call. For example, if your data object has two methods:
事件处理方法示例:
public class MyHandlers {
public void onClickFriend(View view) { ... }
}
布局文件中对点击事件监听器赋值的表达式如下:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="handlers" type="com.example.MyHandlers"/>
<variable name="user" type="com.example.User"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}"
android:onClick="@{handlers::onClickFriend}"/>
</LinearLayout>
</layout>
注意:表达式中方法的签名必须和监听器对象中的方法签名完全保持一致。
在Activity文件中创建绑定关系,可以看到需要设置布局文件中定义的两个variable:user和handlers
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
ActivityMain2Binding binding = DataBindingUtil.setContentView(this, R.layout.activity_main2);
User user = new User("Test", "User");
binding.setUser(user);
binding.setHandlers(new MyHandlers());
}
监听器绑定
官方说明:These are lambda expressions that are evaluated when the event happens. Data Binding always creates a listener, which it sets on the view. When the event is dispatched, the listener evaluates the lambda expression.
Listener Bindings are binding expressions that run when an event happens. They are similar to method references, but they let you run arbitrary data binding expressions. This feature is available with Android Gradle Plugin for Gradle version 2.0 and later.
在方法引用事件处理中,方法的参数必须和事件监听器的一致。而在监听器绑定事件处理中,只要求返回值和监听器的保持一致,除非监听器返回空。示例:
public class Presenter {
public void onSaveClick(Task task){}
}
绑定点击事件方法示例:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="task" type="com.android.example.Task" />
<variable name="presenter" type="com.android.example.Presenter" />
</data>
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent">
<Button android:layout_width="wrap_content" android:layout_height="wrap_content"
android:onClick="@{() -> presenter.onSaveClick(task)}" />
</LinearLayout>
</layout>
监听器使用lambda表达式,只能作为表达式的根元素。当在表达式中使用回调时,Data Binding自动创建必要的监听器并注册事件。当view触发事件时,Data Binding对表达式进行求值。
As in regular binding expressions, you still get the null and thread safety of Data Binding while these listener expressions are being evaluated.
上例中并未定义点击onClick(android.view.View)中传入的view参数。关于监听器参数,有两种选择:一忽略所有的参数;二命名所有参数。如果选择命名这些参数,则可以在表达式中使用。上述表达式也可以写为:
android:onClick="@{(view) -> presenter.onSaveClick(task)}"
如果想在表达式中使用参数,方法如下:
public class Presenter {
public void onSaveClick(View view, Task task){}
}
android:onClick="@{(theView) -> presenter.onSaveClick(theView, task)}"
lamda表达式可以有多个参数。
public class Presenter {
public void onCompletedChanged(Task task, boolean completed){}
}
//监听事件原型 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
<CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content"
android:onCheckedChanged="@{(cb, isChecked) -> presenter.completeChanged(task, isChecked)}" />
如果监听的事件返回值不是空,则表达式中需要返回一样的类型。例如监听长按事件时,需要返回false。
public class Presenter {
public boolean onLongClick(View view, Task task){}
}
//监听事件原型 boolean onLongClick(View var1)
android:onLongClick="@{(theView) -> presenter.onLongClick(theView, task)}"
如果因为null对象导致表达式不能求值,Data Binding返回java中该类型的默认值。e.g. 引用类型返回null,int返回0,boolean返回false,etc.
如果需要使用表达式做判断(如三元组),void可以用来作为一个符号。
android:onClick="@{(v) -> v.isVisible() ? doSomething() : void}"
避免使用复杂的监听器
监听器表达式功能很强大,并让代码更易读。但是,监听器如果使用复杂的表达式会使得布局文件很难阅读和难以维护。这些表达式应该尽量简单,只承担将可用数据从UI传递到回调函数的作用。任何商业逻辑的实现,都应该放在表达式中触发的回调函数中。
参考文档:https://developer.android.google.cn/topic/libraries/data-binding/index.html#build_environment
网友评论