Android DataBinding的官方双向绑定示例

Android DataBinding的官方双向绑定示例,第1张

概述在AndroidStudio2.1Preview3之后,官方开始支持双向绑定了。可惜目前Google并没有在DataBinding指南里面加入这个教程,并且在整个互联网之中只有这篇文章介绍了如何使用反向绑定。

在AndroID Studio 2.1 PrevIEw 3之后,官方开始支持双向绑定了。

可惜目前Google并没有在Data Binding指南里面加入这个教程,并且在整个互联网之中只有这篇文章介绍了如何使用反向绑定。

在阅读一下文章之前,我假设你已经知道如何正向绑定。

回顾一下Data Binding

在正向绑定中,我们在Layout里面的绑定表达式是这样的:

<layout ...> <data>  <variable type="com.example.myapp.User" name="user"/> </data> <relativeLayout ...>  <TextVIEw androID:text="@{user.name}" .../> </relativeLayout></layout>

当user.name的数据改动时,我们的TextVIEw都会同步改变文字。

双向绑定

现在假设一种情况,当你更换成EditText时,如果你的用户名User.name已经绑定到EditText中,当用户输入文字的时候,你原来的user.name数据并没有同步改动,因此我们需要修改成:

<layout ...> <data>  <variable type="com.example.myapp.User" name="user"/> </data> <relativeLayout ...>  <EditText androID:text="@={user.name}" .../> </relativeLayout></layout>

看出微小的差别了吗?对,就是"@{}"改成了"@={}",是不是很简单?

隐式引用属性

同样你也可以在别的VIEw上引用属性:

<layout ...> <data>  <import type="androID.vIEw.VIEw"/> </data> <relativeLayout ...>  <CheckBox androID:ID="@+ID/seeAds" .../>  <ImageVIEw androID:visibility="@{seeAds.checked ? VIEw.VISIBLE : VIEw.GONE}" .../> </relativeLayout></layout>

当CheckBox的状态发生改变的时候,ImageVIEw也会同时发生改变。在复杂情况下,这个特性没什么卵用,因为逻辑部分我们是不建议写在XML中。

如何开启双向绑定

开启双向绑定,需要在项目的build.gradle中设置:

classpath 'com.androID.tools.build:gradle:2.1.0-Alpha3'

同样,你需要在你Module的build.gradle中设置:

androID {  ...  dataBinding.enabled = true}

貌似还有点问题

我们刚才的例子里面只显示了系统自带的应用,那么如果是自定义控件,或者是我们更细颗粒度的Observable呢?等下就揭晓如何自定义自己的双向绑定,我们来看看目前AndroID支持的控件:

AbsListVIEw androID:selectedItemposition CalendarVIEw androID:date Compoundbutton androID:checked DatePicker androID:year,androID:month,androID:day NumberPicker androID:value RadioGroup androID:checkedbutton ratingbar androID:rating Seekbar androID:progress TabHost androID:currentTab (估计没人用) TextVIEw androID:text TimePicker androID:hour,androID:minute

自定义双向绑定

设想一下我们使用了下拉刷新SwipeRefreshLayout控件,这个时候我们希望在加载数据的时候能控制refreshing的状态,所以我们加入了ObservableBoolean的变量swipeRefreshVIEwRefreshing来正向绑定数据,并且能够在用户手动下拉刷新的时候同步更新swipeRefreshVIEwRefreshing数据:

// SwipeRefreshLayout.javapublic class SwipeRefreshLayout extends VIEw {  private boolean isRefreshing;  public voID setRefreshing() {/* ... */}  public boolean isRefreshing() {/* ... */}  public voID setonRefreshListener(OnRefreshListener Listener) {    /* ... */  }  public interface OnRefreshListener {    voID onRefresh();  }}

接下来我们需要告诉框架,我们需要将SwipeRefreshLayout的isRefreshing的值反向绑定到swipeRefreshVIEwRefreshing

@InverseBindingMethods({    @InverseBindingMethod(        type = androID.support.v4.Widget.SwipeRefreshLayout.class,attribute = "refreshing",event = "refreshingAttrChanged",method = "isRefreshing")})

这是一种简单的定义,其中event和method都不是必须的,因为系统会自动生成,写出来是为了更好地了解如何绑定的,可以参考官方文档InverseBindingMethod。

当然你也可以使用另外一种写法,并且如果你的值并不是直接对应Observable的值的时候,就可以在这里进行转换:

@InverseBindingAdapter(attribute = "refreshing",event = "refreshingAttrChanged")public static boolean isRefreshing(SwipeRefreshLayout vIEw) {  return vIEw.isRefreshing();}

上面的event同样也不是必须的。以上的定义都是为了让我们能够在布局文件中使用"@={}"这个双向绑定的特性。接下来你需要告诉框架如何处理refreshingAttrChanged事件,就像处理一般的监听事件一样:

@BindingAdapter("refreshingAttrChanged")public static voID setonRefreshListener(final SwipeRefreshLayout vIEw,final InverseBindingListener refreshingAttrChanged) {  if (refreshingAttrChanged == null) {    vIEw.setonRefreshListener(null);  } else {    vIEw.setonRefreshListener(new OnRefreshListener() {      @OverrIDe      public voID onRefresh() {        colorChange.onChange();      }    });  }}

一般情况下,我们都需要设置正常的OnRefreshListener,所以我们可以合并写成:

@BindingAdapter(value = {"onRefreshListener","refreshingAttrChanged"},requireAll = false)public static voID setonRefreshListener(final SwipeRefreshLayout vIEw,final OnRefreshListener Listener,final InverseBindingListener refreshingAttrChanged) {  OnRefreshListener newValue = new OnRefreshListener() {    @OverrIDe    public voID onRefresh() {      if (Listener != null) {        Listener.onRefresh();      }      if (refreshingAttrChanged != null) {        refreshingAttrChanged.onChange();      }    }  };  OnRefreshListener oldValue = ListenerUtil.trackListener(vIEw,newValue,R.ID.onRefreshListener);  if (oldValue != null) {    vIEw.setonRefreshListener(null);  }  vIEw.setonRefreshListener(newValue);}

现在我们终于可以使用双向绑定的技术啦。但是要注意,需要设置requireAll = false,否则系统将识别不了refreshingAttrChanged属性,前文提到的文章例子里并没有设置这个。

在viewmodel中,我们的数据是这样的:

// Myviewmodel.javapublic final ObservableBoolean swipeRefreshVIEwRefreshing = new ObservableBoolean(false);public voID load() {  swipeRefreshVIEwRefreshing.set(true);  // 网络请求  ....  swipeRefreshVIEwRefreshing.set(false);}public SwipeRefreshLayout.OnRefreshListener onRefreshListener() {  return new SwipeRefreshLayout.OnRefreshListener() {    @OverrIDe    public voID onRefresh() {      // Do something you need    }  };}

在布局文件中是这样设置的:

<androID.support.v4.Widget.SwipeRefreshLayout  androID:ID="@+ID/swipe_refresh_vIEw"  androID:layout_wIDth="match_parent"  androID:layout_height="match_parent"  app:onRefreshListener="@{viewmodel.onRefreshListener}"  app:refreshing="@={viewmodel.swipeRefreshVIEwRefreshing}">  ...</androID.support.v4.Widget.SwipeRefreshLayout>

最后我们还有一个小问题,就是双向绑定有可能会出现死循环,因为当你通过Listener反向设置数据时,数据也会再次发送事件给VIEw。所以我们需要在设置一下避免死循环:

@BindingAdapter("refreshing")public static voID setRefreshing(SwipeRefreshLayout vIEw,boolean refreshing) {  if (refreshing != vIEw.isRefreshing()) {    vIEw.setRefreshing(refreshing);  }}

这样就没问题啦。以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。

总结

以上是内存溢出为你收集整理的Android DataBinding的官方双向绑定示例全部内容,希望文章能够帮你解决Android DataBinding的官方双向绑定示例所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1144001.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存