Android里的DataBinding

为什么我们需要Data Binding

传统的MVC模式如下图所示:

mvc这种模式的初衷是让业务逻辑和View分开,让我们在修改界面而不改变业务逻辑的时候更简单,但是实习操作的时候往往很难完全对View和Controller或Model很好的分离。并且三种组件也增加了一定的复杂度。而当我们有了Data Binding技术我们就可以使用另外一种模式(这种模式常用于Windows软件开发)叫MVVM 全称是Model-View-ViewModel,Model代表的是你的业务逻辑,View是展示的视图,ViewModel是把二者绑定起来的接口。这样说还是有点抽象,在一般Android开发里,如果某个View展示的数据出现了变化,我们需要findViewById找到这个View,并且设置新更新的数值。而在MVVC里,因为Model和View是绑定的,如果model层的数据发送了变化,会自动通知更新view应该如何重新变化展示。听起来是不是非常棒哈。

 如何在Android里使用
  • 准备环境

在整个工程里的build.gradle里添加如下依赖:


 
 
1
2
3
4
   dependencies  {
        classpath  "com.android.tools.build:gradle:1.3.0-beta1"
        classpath  "com.android.databinding:dataBinder:1.0-rc0"
    }

在你需要的使用data binding的module对应的build.gradle里添加

apply plugin: 'com.android.databinding'

ps:这里需要Android Studio是1.3以上,gradle版本在1.3以上,我之前即使是这样设置了还是有问题,我把build tool还有兼容包全部升级到最新版本就木有问题了。

下面我将已一个例子来介绍Android的DataBinding,这个小程序叫MagicNumber,app里显示一个数从1开始,有一个按钮,按一次按钮数字加1,若数字是奇数数字将显示黄色,若是偶数显示蓝色。

 

 

evenodd

先写布局:


 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?xml version="1.0" encoding="utf-8"?>
< layout  xmlns:android = "http://schemas.android.com/apk/res/android" >
     < data >
         < variable  name = "num"  type = "com.lvable.databindingtest.MagicNumber" />
     </ data >
     < RelativeLayout
         android:layout_width = "match_parent"
         android:layout_height = "match_parent" >
         < TextView
              android:layout_width = "wrap_content"
              android:layout_height = "wrap_content"
              android:textSize = "30sp"
              android:text = "The magic number"
              android:id = "@+id/textView"
              android:layout_marginTop = "43dp"
              android:layout_alignParentTop = "true"
              android:layout_centerHorizontal = "true" />
         < TextView
              android:id = "@+id/textView2"
              android:layout_width = "wrap_content"
              android:layout_height = "wrap_content"
              android:layout_marginTop = "67dp"
              android:textSize = "60sp"
              android:layout_below = "@+id/textView"
              android:layout_centerHorizontal = "true"
              android:text = "@{num.num}"
              android:textColor = "@{num.odd ? @color/light_yellow : @color/light_blue}"
              />
         < Button
              android:text = "Add"
              android:id = "@+id/btn"
              android:onClick = "addCount"
              android:layout_below = "@id/textView2"
              android:layout_centerHorizontal = "true"
              android:layout_marginTop = "20dp"
              android:layout_width = "wrap_content"
              android:layout_height = "wrap_content" />
     </ RelativeLayout >
</ layout >

注意如下变化:布局文件里的根元素不再是ViewGroup而是一个叫layout的标签,这个标签里包含一个data标签还有一个View,data标签里面包含了要绑定的数据元素类型申明等信息。在本例子里,我们要绑定的数据类型叫MagicNumber,然后在布局里它的名字叫num,type是这个类的完整路径名(若是Java自带的类型直接写就好,比如String,int)。在其他地方若要用到这个绑定数据的值只需要用@ {obj.xxxx}就行。这里要注意一个问题,就是在访问obj的成员变量的时候不一定总是它的全名,我试了一下我的MagicNumber里有一个成员变量叫isOdd,但是要访问它的话我要这样写 @{num.odd}。在这里还可以使用一些语句来实现简单的逻辑操作,比如我在布局文件里写入了奇偶不同颜色不同的逻辑。在textView里

android:textColor="@{num.odd ? @color/light_yellow : @color/light_blue}"

带Observable模式的MagicNumber类

Observable模式就是,当绑定的数据发送变化的时候,这个绑定的View会自己更新显示信息。这里可以使用MagicNumber继承一个叫BaseObservable的类来实现。(也可以使用ObservableField来实现对某一个field的Observe而不用继承)。


 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package  com. lvable. databindingtest;
import  android. databinding. BaseObservable;
import  android. databinding. Bindable;
import  com. lvable. databindingtest. BR;
/**
 * Created by Jiaqi Ning on 21/6/2015.
 */
public  class  MagicNumber  extends  BaseObservable {
     private  String  num;
     private  boolean  isOdd;
    
     public  MagicNumber( int  num){
         this. num  =  Integer. toString( num);
    }
   
    @ Bindable
     public  String  getNum() {
         return  num;
    }
   
    @ Bindable
     public  boolean  isOdd() {
         return  isOdd;
    }
    
     public  void  addOne(){
         int  c  =  Integer. parseInt( num);
         num  =  Integer. toString( ++ c);
         updateEven();
         notifyPropertyChanged( BR. num);
         notifyPropertyChanged( BR. odd);
    }
     private  void  updateEven(){
         int  c  =  Integer. parseInt( num);
         isOdd  = (( c  %  2! =  0) ?  true :  false;
    }
}

这里要注意,需要有更新通知功能的成员变量的get方法里,添加@Bindable这个注解,然后在起更新数据的地方调用对应的notifyPropertyChanged(BR.xxx)。在本程序里是如果MagicNumber调用了addOne就通知数据更新。

(注:BR 是编译阶段生成的一个类,功能与 R.java 类似,用 @Bindable 标记过 getter 方法会在 BR 中生成一个 entry,当我们通过代码可以看出,当数据发生变化时还是需要手动发出通知。)

好了,终于到了最后真正实现绑定的一步了!


 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public  class  MainActivity  extends  AppCompatActivity {
     MagicNumber  magicNumber  =  new  MagicNumber( 1);
    @ Override
     protected  void  onCreate( Bundle  savedInstanceState) {
         super. onCreate( savedInstanceState);
         ActivityMainBinding  binding  =  DataBindingUtil. setContentView( thisR. layout. activity_main);
         binding. setNum( magicNumber);
    }
     public  void  addCount( View  view){
         magicNumber. addOne();
    }
}

注意,这里不再使用setContentView(),使用的DataBindingUtil.setContentView()返回一个binding,用它来绑定数据。(这里的set方法是更具之前data里写入的type动态生成的)。

还有一个更好用的特性,若你在布局文件里给了某个View一个ID,在Activity里你想要使用这个View你不再需要些findViewById,你只需要从前面绑定产生的那个binding.xxxx (xxx是view的id名)就可以直接对这个View进行操作了!Awesome!

参考:    Google官方guide

很好的binding demo教程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值