Databinding使用(java)

个人使用学习过程,感谢指出错误

集成

在要使用的module的build.gradle文件中添加如下就可以使用了

android {
    ...
    dataBinding {  //databinding
        enabled = true
    }
}

基础使用

使用之前要知道Databinding都能做什么? 简单的理解就是 省去早先findViewById()的相关操作 把操作都写在了xml文件中,那么xml文件就需要变得不一样

1. 改变xml的格式满足Databinding规则

image.png

在xml的根标签Alt + Enter就可以看到如下界面选择 Convert to data binding layout
会发现多了一个 data 标签 我们相关的数据就要放在data标签中
layout标签的直接子标签不能是merge,否则报错

2. 如何把数据引用到xml里

public class Bean1 {
    public Bean1(String name, int count, int total) {
        this.name = name;
        this.count = count;
        this.total = total;
    }

    private String name;
    public int count;
    public int total;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public int getTotal() {
        return total;
    }

    public void setTotal(int total) {
        this.total = total;
    }
}

我们新建一个Bean引用数据毋庸置疑就是引用Bean1到data标签中

//第一种引入方式
    <data>
        <variable
            name="bean"
            type="com.xiaoyu.jetpack.dataBinding.bean.Bean1" />
    </data>
//第二种引入方式
     <data>
        <import type="com.xiaoyu.jetpack.dataBinding.bean.Bean1"
                alias="bean2"/> //设置别名
        <variable
            name="bean"
            type="Bean2" />
    </data>

如果引入相同名称的数据 import中可以设置别名

数据引用完成后就要把数据关联到对应的控件上了


image.png
  1. 只需要在设置文字时用@{ }然后在{}里获取数据就可以了如此简单
  2. 需要注意的是类型问题如果设置的数据不是String类型可以String.valueOf()方法转换一下
  3. 我们在开发的时候需要做界面调试文字颜色之类的没有界面不是很方便就可以给个默认值有两种方法直接写用字符串的引用个人推荐第二种

3. 代码绑定数据

上面所有的准备工作都已经做好了可是我们的bean中没有数据啊没有数据就没有显示啊
(不晓得为什么xml中设置的默认文字运行项目的时候也不显示)
接下来就说说数据是如何绑定的 (相信我特别难!!)

 Activity1Binding binding = DataBindingUtil.setContentView(this, R.layout.activity1);//上面的布局
 binding.setBean(new Bean1("apple", 1, 10));

上面代码的意思呢就是我要把xml和这个这个activity关联然后返回给我一个Activity1Binding实例
这个实例类是系统自动生成的命名规则就是你指定的xml文件名除去 _ 加上Binding后缀
第二行代码就是填充数据了执行代码就出现文字了

image.png

4. 在Fragment中绑定数据

public class FragmentBinding extends androidx.fragment.app.Fragment {

    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        Activity1LayoutBinding inflate = DataBindingUtil.inflate(inflater, R.layout.activity1_layout, container, false);
        inflate.setBean(new Bean1("apple",2,20));
        return inflate.getRoot();
    }
}

数据与UI更新(单向绑定/双向绑定)

这块要说的是数据更改之后UI进行界面更新这里分为单向绑定双向绑定
单向绑定应用场景 : 数据更新后刷新UI
双向绑定应用场景 : Edittext文本输入文字同时更改TextView显示为输入的文字

1. 单向绑定之BaseObservable

先分析一波,数据更新后刷新UI,数据在哪里?当然是bean喽~绑定要在哪里做手脚?当然也是bean喽

创建bean继承BaseObservable

public class Bean2 extends BaseObservable {
    //如果是public在成员变量上注解
 //如果是 private的在get方法上添加注解
    @Bindable
    public String name;
   //如果是 private的在get方法上添加注解
    private int price;
    public int total;

    public Bean2(String name, int price, int total) {
        this.name = name;
        this.price = price;
        this.total = total;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
        notifyPropertyChanged(com.xiaoyu.jetpack.BR.name);
    }
 
    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
        notifyChange();
    }

    public int getTotal() {
        return total;
    }

    public void setTotal(int total) {
        this.total = total;
    }
}

创建layout

<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>

        <variable
            name="bean"
            type="com.xiaoyu.jetpack.dataBinding.bean.Bean2" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TextView
            android:gravity="center"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:text="@{bean.name}" />

        <TextView
            android:gravity="center"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:text="@{String.valueOf(bean.price)}" />

        <TextView
            android:gravity="center"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:text="@{String.valueOf(bean.total)}" />

        <Button
            android:onClick="change1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="更改name和total"/>
        <Button
            android:onClick="change2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="更改price和total"/>
    </LinearLayout>
  1. 标注注解就是为了提供指定数据对应的UI的更新如果需求是全部更新可以不标注
  2. 继承于BaseObservable 会有几个公有方法
    notifyChange();代表的是全部更新
    notifyPropertyChanged(fileid); 这个fileid就是标注了@Bindable注解之后系统自动生成的没有的话就冲新build一下

完成上面的bean的书写等同于已经完成了数据绑定 不信? 有代码为证

public class Activity2 extends AppCompatActivity {

    private Bean2 bean2;
    private Activity3LayoutBinding binding3;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Activity2LayoutBinding binding = DataBindingUtil.setContentView(this, R.layout.activity2_layout);
        bean2 = new Bean2("apple", 1, 1);
        binding.setBean(bean2);

//        binding.addOnPropertyChangedCallback(new Observable.OnPropertyChangedCallback() {
//            @Override
//            public void onPropertyChanged(Observable sender, int propertyId) {
                //  todo 这里可以区别出不同的fileid
//            }
//        });

    }

    public void change1(View view) {
        bean2.setName("apple" + new Random().nextInt(10));
        bean2.setTotal(new Random().nextInt(100));

    }

    public void change2(View view) {
        bean2.setPrice(new Random().nextInt(10));
        bean2.setTotal(new Random().nextInt(100));
    }


2. 单向绑定之ObservableField

BaseObservable的方式更新数据有些麻烦优点就是可以指定刷新可是多数场景没有这个需求就可以用简单的 ObservableField
两种方式的主要区别依然是bean

public class Bean3  {
  private ObservableField<String> name;
  private ObservableField<Integer> price;
  private ObservableField<Integer> total;

    public ObservableField<String> getName() {
        return name;
    }

    public void setName(ObservableField<String> name) {
        this.name = name;
    }

    public ObservableField<Integer> getPrice() {
        return price;
    }

    public void setPrice(ObservableField<Integer> price) {
        this.price = price;
    }

    public ObservableField<Integer> getTotal() {
        return total;
    }

    public void setTotal(ObservableField<Integer> total) {
        this.total = total;
    }

可以看到直接用ObservableField指定泛型来代替原有的类型
注意! ! ! 不用继承任何类
除此之外没有任何不同

layout代码

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>

        <variable
            name="bean"
            type="com.xiaoyu.jetpack.dataBinding.bean.Bean3" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TextView
            android:gravity="center"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:text="@{bean.name}" />

        <TextView
            android:gravity="center"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:text="@{String.valueOf(bean.price)}" />

        <TextView
            android:gravity="center"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:text="@{String.valueOf(bean.total)}" />

        <Button
            android:onClick="change3"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="ObservableField更改数据"/>
    </LinearLayout>
</layout>

activity代码

public class Activity3 extends AppCompatActivity {

    private Bean3 bean3;
    private Activity3LayoutBinding binding3;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding3 = DataBindingUtil.setContentView(this, R.layout.activity3_layout);
        bean3 = new Bean3();
        bean3.setName(new ObservableField<String>("apple"));
        bean3.setPrice(new ObservableField<Integer>(10));
        bean3.setTotal(new ObservableField<Integer>(100));
        binding3.setBean(bean3);


    }


    public void change3(View view) {
        bean3.getName().set(new Random().nextInt(10) + "");
        bean3.getPrice().set(new Random().nextInt(30));
        bean3.getTotal().set(new Random().nextInt(100));
    }

}

看一下change3()这个方法有没有很别扭? 对没有看错设置数据的时候用的get()
而不是bean3.setName(new ObservableField<String>());好奇的我实验了一下 set的话是不现实更新数据的 ( 避坑各位 !! )

3. 双向数据绑定

双向数据绑定就是在ObservableField基础上进行的
只需要在xml文件里加入如下控件就可以实现了(Edittext在输入的时候显示name的控件也会跟着改变显示内容)

      <EditText
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:text="@={bean.name}" />

事件的绑定(类似于回调接口)

老三样:bean,activity,xml
--------------------------------bean--------------------------------


public class Bean4 {
private String name;
private String pwd;

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

--------------------------------activity--------------------------------

public class Activity4 extends AppCompatActivity {

    private Activity4LayoutBinding binding;
    private Bean4 bean4;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this, R.layout.activity4_layout);
        bean4 = new Bean4();
        bean4.setName("小明");
        bean4.setPwd("123");
        binding.setBean(bean4);
        binding.setClick(new BindClick());

    }
  //toast当前的name
    public class BindClick {
        public void ToastClick(Bean4 bean4) {
            Toast.makeText(Activity4.this, bean4.getName() + "", Toast.LENGTH_SHORT).show();
        }
    // 名字更改时更新bean
        public void afterTextChanged(Editable s) {
            bean4.setName(s.toString());
            binding.setBean(bean4);
        }
  //pwd更改时更新bean
        public void afterpwdChanged(Editable s) {
            bean4.setPwd(s.toString());
            binding.setBean(bean4);
        }
    }
}

--------------------------------xml--------------------------------

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>

        <variable
            name="bean"
            type="com.xiaoyu.jetpack.dataBinding.bean.Bean4" />

        <variable
            name="click"
            type="com.xiaoyu.jetpack.dataBinding.activity.Activity4.BindClick" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <Button
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:onClick="@{()->click.ToastClick(bean)}"
            android:text="Toast测试" />


        <TextView
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:gravity="center"
            android:text="@{bean.name,default = name}" />
        <TextView
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:gravity="center"
            android:text="@{bean.pwd,default = pwd}" />

        <EditText
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:afterTextChanged="@{click.afterTextChanged}"
            android:hint="name" />

        <EditText
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:afterTextChanged="@{click.afterpwdChanged}"
            android:hint="pwd" />

    </LinearLayout>
</layout>

先说 activity 设置好数据 再把数据给到xml没问题
为了方便创建了BindClick内部类里面有几个点击的方法(名字随便参数要准确)
跟到xml中发现点击事件()->click.ToastClick(bean) ( 这没啥说的吧 背下来可好 )
再看Edittext 的监听(改变监听) 有啥不一样? 参数没有了发现没 所以自己用的时候注意
还记得如何在xml文件中定义click事件不?有异曲同工之妙
同样的这种调用方式也适合调用工具类 ( 前提是要把工具类导入进来 )

数据传递与懒加载

这里的数据传递是xml之间的数据传递
懒加载的方式 ViewStub

1. 数据传递

因为databinding所有的数据都是要在xml中进行赋值,当我们使用include的时候的数据要怎么把数据传递过去呢

----------主页布局----------
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:bind="http://schemas.android.com/apk/res-auto">

    <data>

        <import type="com.xiaoyu.jetpack.dataBinding.bean.Bean5" />

        <variable
            name="bean"
            type="Bean5" />

    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <include
            layout="@layout/includ_ayout"
            bind:includeBean="@{bean}" />
    </LinearLayout>
</layout>


----------include的布局----------

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <import type="com.xiaoyu.jetpack.dataBinding.bean.Bean5"/>
        <variable
            name="includeBean"
            type="Bean5" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:gravity="center"
            android:text="@{bean.name}" />

    </LinearLayout>
</layout>

看似简单其实细节很重要总结了一下两点

  1. 在数据传递到include布局中时使用的 bind: nextname = "@{ ** }" nextname 的命名要和include中的name保持一致 (一定注意)
  2. include布局中也是要引入<variable>标签的

2. 懒加载ViewStub

这个懒加载细节性问题比较多因为粗心它浪费了我很多的时间

--------------------------------------主布局--------------------------------------
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:bind="http://schemas.android.com/apk/res-auto">

    <data>
        <variable
            name="bean"
            type="com.xiaoyu.jetpack.dataBinding.bean.Bean5" />

    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <Button
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:onClick="showLayout"
            android:text="显示ViewStub" />

        <ViewStub
            android:id="@+id/view_stub"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout="@layout/stub_layout"
            bind:bean="@{bean}" />
    </LinearLayout>
</layout>
--------------------------------------StubView布局--------------------------------------
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <import type="com.xiaoyu.jetpack.dataBinding.bean.Bean5" />
        <variable
            name="bean"
            type="Bean5" />
    </data>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:padding="40dp"
        android:text="@{bean.name}" />
</layout>

activity代码(bean就不贴了,只有一个字段)

public class Activity5 extends AppCompatActivity {


    private static final String TAG = "ACTIVITY_5";
    private Activity5LayoutBinding binding;
    private Bean5 bean5;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this, R.layout.activity5_layout);
        bean5 = new Bean5();
        bean5.setName("小明");
        binding.setBean(bean5);
        binding.viewStub.setOnInflateListener(new ViewStub.OnInflateListener() {
            @Override
            public void onInflate(ViewStub stub, View inflated) {
                //如果在 xml 中没有对 viewStub 进行数据绑定在此处绑定
                StubLayoutBinding stubBinding = DataBindingUtil.bind(inflated);
                stubBinding.setBean(bean5);
            }
        });
    }
    public void showLayout(View view){
        if (!binding.viewStub.isInflated()) { //只能被inflate一次
            binding.viewStub.getViewStub().inflate();
        }
    }
}

细节补充一下

  1. ViewStub可指定布局 数据的传递的点和上面的include一样
  2. 要通过binding.viewStubId.getViewStub().inflate()来进行加载但是注意只能加载一次否则会报错
  3. 传递数据可以通过xml中 bind: nextname = "@{ ** }" 也可以使用代码绑定
  4. 代码绑定 binding.viewStubId.setOnInflateListener() 之后通过 DataBindingUtil.bind(inflated); 获取的是ViewStub的databinding实例(一定注意!!)
  5. 如果有多个viewStub怎么办如何区分? 不同的viewStub是通过id区分的( 系统会根据id自动生成除去_的id我们直接 binding. 就可以找到 )

github地址

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,616评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,020评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,078评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,040评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,154评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,265评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,298评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,072评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,491评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,795评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,970评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,654评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,272评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,985评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,815评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,852评论 2 351

推荐阅读更多精彩内容