Data Binding(四):事件监听

在之前的文章里,我写了如何在Android App中如何消除FindViewById(),同时解决View IDs的问题。有一件事情是我没有在之前文章中显示出来,即如何处理事件监听,例如View’s OnClickListenerTextView’s TextWatcher

Android Data Binding 提供了三种在布局文件中设置事件监听的机制,你可以选择最适合你的方法。不同于基础的Android OnClick属性,在data binding的实践机制中没有使用反射,所以不论你选择哪一种方法都不会去影响性能。

Listener Objects

在任何一个可以使用set* 调用的listener(并不是add *调用的)的view中,你都可以绑定一个listener到它的属性上。如下:

<View android:onClickListener="@{callbacks.clickListener}" .../>

这个listener可以通过getter定义,或者通过一个public 字段定义:

public class Callbacks {
    public View.OnClickListener clickListener;
}

还有一种简便的方法,即将Listener脱离开:

<View android:onClick="@{listeners.clickListener}" .../>

当应用程序已经使用侦听器对象时,将使用绑定与侦听器对象,但在大多数情况下,你将使用其他两种方法之一。

Method References

通过方法引用,你可以单独的连接方法到任何的事件监听器上。任何静态或者实例的方法都可以使用,只要它们在监听器中有相同的参数以及返回值。例如:

<EditText
    android:afterTextChanged="@{callbacks::nameChanged}" .../>

这个叫nameChanged的回调方法代码如下:

public class Callbacks {
    public void nameChanged(Editable editable) {
        //...
    }
}

这个属性总用在「Android」的明明空间中,并且在监听器中匹配相应名字的方法。

即使它不被建议,你可以在绑定的时候做一些逻辑处理:

<EditText android:afterTextChanged=
    "@{user.hasName?callbacks::nameChanged:callbacks::idChanged}"
    .../>

在大多数情况下把逻辑放在调用的方法里面是好的选择。当你将其他的信息传递给方法(如上面的user),这会变得更加的容易。你也可以通过lambda表达式做上面的事情。

Lambda Expressions

你可以提供一个lambda表达式,给你的方法里面传递任何参数。例如:

<EditText
 android:afterTextChanged="@{(e)->callbacks.textChanged(user, e)}"
 ... />

textChanged方法接收传过来的参数:

public class Callbacks {
    public void textChanged(User user, Editable editable) {
        if (user.hasName()) {
            //...
        } else {
            //...
        }
    }
}

要是你的监听器中没有参数,你可以移除它们:

<EditText
 android:afterTextChanged="@{()->callbacks.textChanged(user)}"
 ... />

但是你无法只使用其中的几个—它们要不全在要不都不在。

表达式求值的时间在方法引用和lambda表达式之间也不同。通过方法引用,在绑定的时候验证表达式。使用lambda表达式,会在时间发生时候验证。

假设,回调的变量没有被设置。通过方法引用,表达式验证为空,不会有监听器被设置。通过Lambda表达式,监听器一直被设置,当事件发生时候验证表达式。通常这并不重要,但是当有一个返回值时,将返回默认的Java值,而不是没有调用。 例如:

<View android:onLongClick=”@{()->callbacks.longClick()}” …/>

当回调是空的时候,将会返回false。你可以使用一个长的表达式来将返回值设定成你所希望的:

<View android:onLongClick=”@{()->callbacks == null ? true : callbacks.longClick()}” …/>

你通常只是通过确保你没有null表达式求值来完全避免这种情况。

Lambda表达式和方法引用可以作用在相同的属性上,所以你可以方便的切换它俩。

挑选哪一个?

最灵活的方式当然是lambda表达式,它允许您为事件监听器提供的回调提供不同的参数。

在许多情况下,你的回调将采用与侦听器方法中给定的完全相同的参数。 在这种情况下,方法引用提供较短的语法,并且稍微更容易阅读。

在要转换为使用Android Data Binding的应用程序中,你可能已经在视图上设置了监听器对象。 您可以将侦听器作为变量传递到布局,并将其分配给视图。

原始文章地址(https://medium.com/google-developers/android-data-binding-adding-some-variability-1fe001b3abcc#.9zu7zob81)


历史文章记录:

  1. Data-Binding(一):别在使用FindViewById()了
  2. Data-Binding(二):include标签的使用
  3. Data-Binding (三):让View-Id不再那么必要
  4. Data Binding(四):事件监听