DataBinding学习使用进阶之路

最近在学习DataBinding的使用,中间遇到了不少的坑,记录以下,帮助以后学习DataBinding的朋友。

一:引入

其实,我们只需要在对应的Module的build.gradle中添加这么一句话即可。

dataBinding {
    enabled=true
}

不需要加别的东西。

二:简单使用的时候我出现的错误

1.比如这么写

android:text="@{User.name}"/>

那么,我User中的成员变量name,必须是String类型的。因为DataBinding不是使用反射的,你必须公有化才能访问得到。否则会报找不到类,···javac什么的异常。

2.比如我这么写

android:text="@{User.age}

那么,我的age这个成员变量必须是String类型的,如果使用int类型的话,程序会crash掉
但如果必须是int类型,那么该怎么写呢,可以这么写

android:text="@{String.valueOf(user.age)}"

因为这个android:text 中是 String 类型

3.比如我这么写

ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);

ActivityMainBinding这个类又是来自于哪里?他是根据R.layout.activity_main来生成的。如果我的布局文件是main_activity,那么就应该生成MainActivityBinding。

三:开始使用

引入DataBinding的时候我遇到过以上的错误,之后就让我们一起学习DataBinding的使用吧。
我推荐大家把这个Demo下载下来,跟着源码去读一读,感受一下功能和写法
DataBindingDemo
而今天,我们就是去Read The Fucking Source Code。
首页是这样的,我们一个一个进去看

1:A SIMPLE BASIC EXAMPLE

这个比较简单,建议读者自己能跟着代码走一遍,有什么不懂得可以留言,我们一起探讨进步。
说几个需要注意的地方

android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"//支持三元运算符。需要导入View包
android:text="@{String.valueOf(user.age)}"//前面说了,@{只能是String},为什么,可以看3.1,匹配规则
android:text="@{StringUtils.capitalize(user.firstName)}"//前面导入了这个包,可以调用这个静态方法
android:text="@{user.displayName ?? user.lastName}"//它表达的是如果左边不是 null 的,那么使用左边的值,否者使用右边的值。在棉花糖的文章里有介绍

2:CustomBinding

这个的重点在这里

ContractBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_custom_binding);

看到了没,xml是activity_custom_binding,但是这个类却是ContractBinding
他是在这里声明过了的

data class=".ContractBinding"//除了使用框架自动ActivityCustomBinding,我们也可以通过这种方式自定义类名

3:INCLUDES

从这里开始要说的东西就多了。。。。建议刚入门的读者能耐心的看完

3.1万物皆对象

不知道读者有没有想过,为什么binding这个对象会有binding.setUser()这个方法呢?而我们当前看的这个Activity为什么会有

binding.setListener(this);
binding.setOkText("to toast");

这两个方法呢?

因为我们在data中声明过这些东西

<data> 
   <import type="com.liangfeizc.databinding.model.User" />     
     <variable       
        name="user"
        type="User" />
    <variable
        name="listener"      
        type="com.liangfeizc.databinding.listener.OkListener" />    
  <variable
        name="okText"
        type="String" />
</data>

name中标识的user,listener,okText,就是binding所具有的属性,而属性就应该具有set.get方法,这就是万物皆对象,而后面的type,就是属性名的类型。这么说理解吗?很简单,把Binding当做一个对象,万物迎刃而解。
还有一处用到这个思想,问题迎刃而解,我们看include这个布局,有三个自定义的命名空间:

bind:user="@{user}"
bind:okText="@{okText}"
bind:listener="@{listener}"

这就是给他赋值的。这里,我推荐大家看一下https://realm.io/cn/news/data-binding-android-boyar-mount/
棉花糖的对自动属性的介绍。然后我说一下我的理解。

 <variable       
        name="user"
        type="com.liangfeizc.databinding.model.User" />

首先声明这一个变量,让我们的Binding对象具备了

private User user;

这一个属性,而我在布局文件中,可以任意的使用我自己的成员变量user。
这个时候,我可以自定义一个命名空间,并给我的任意控件添加任意属性
比如说

<include
    layout="@layout/layout_btn_ok"
    bind:okText="@{okText}"
    bind:listener="@{listener}"/>

<include>这个标签怎么会有这两个属性,毫无疑问是自动加上去的。那么它又该如何理解呢?
我们使用了 bind:okText这个属性,但实际上该标签并没有提供这么一个 xml 布局属性。这个时候我们就可以想一想自动绑定。xml属性不也是对象的一个属性吗?既然是属性,那么就有set,get。那么我们可以这么想,

private String okText;//如果我后面的@{okText},就是String类型的我就会自动匹配过去。
private OkListener listener;//如果我后面的@{listener},就是OkListener类型的我也会自动匹配过去。

不知道这么说大家有没有理解。这里不好想,一定要自己多看几遍代码,多思考一下。慢慢来。没必要急躁。

3.2···id的作用

不知道大家有没有为这种写法而感到诧异

binding.layoutInput.etName.addTextChangedListener(null);

我去这是什么啊!~这是id。我们可以ctrl点进去看一看。

android:id="@+id/layout_input"
android:id="@+id/et_name"

只要给 View 定义一个 ID,Data Binding 就会为我们生成一个对应的 final变量。以_为单词的分隔符,命名符合java规范。

3.3 点击事件

如果大家看过棉花糖的教程,就会看,这是什么啊,就不能说的细一点吗?

<Button android:onClick="clicked" …/>
<Button android:onClick="@{handlers.clicked}" …/>
<Button android:onClick="@{isAdult ? handlers.adultClick :handlers.childClick}" …/> 
<Button android:onTextChanged="@{handlers.textChanged}" …/>

其实不难想。第一个就是我们平常最常用的点击事件的写法,和databinding没有关系啊。
剩下的都是一个模子出来的。
官方的建议是将事件都写到一起。
就比如代码的作者是这么写的

public interface OkListener {
    void onClickOk(View view);}

然后让

android:onClick="@{listener.onClickOk}"

在执行时候就和我们平时使用差不多了

binding.setListener(this);

就这几步,让你省去了fbc的烦恼。不过,我宁愿想给每一个按钮写一个ID,我也不想给每一个按钮写一个方法名!!!

3.3 include

其实说了那么多,到现在才进入正题。不知道您又学会了多少,学习千万别急,慢慢来,别人的东西只能给你说以下有这么一个东西,具体的还是需要自己多思考的。
闲话:曾经我一直觉得,啊,我会这么多三方库,什么功能都能实现,我要上天了。虽说君子善假于物也,但轮子谁都会滚,却不是我这样的坐井观天,沾沾自喜,仅会简单的使用。我现在想要改变这种状况,尝试着去读各种demo的源码,有时候也是看的头蒙蒙的,感觉会的越来越少,也有些急躁,一旦急躁什么东西都是学不下去的····难受极了。不过,我现在放正了心态,慢慢来学,缓慢而不懈怠,总有一天,一通百通。共勉,加油,我们是第一,我们是最棒的!!!
说了这么多闲话,其实是为了掩饰我内心的恐惧,因为我根本不知道,为什么要在include引用的布局内再写一遍data啊!
我是这么猜测的:
数据绑定,一个大布局对应一个数据源。比如说我这个数据源有5份数据,我这个大布局中有三个小布局,第一个小布局需要1份数据,第二个需要两份数据,第三个需要5份数据。我可以按照这三个小布局声明的需求来去给他们分配。而分配这个动词,就对应了3.1中的自动属性来解决,就是填充!
而且可以保证数据源相对于这个布局的唯一。
我是这么猜的不知道你们那。
include就说这么多,还需要再看,这一个代码写的很好看。

4.Collection

这里讲的是集合作为数据源的使用,集合作为数据源用到的地方还是蛮多的。

4.1需要注意的地方

java.lang包下的类,如String什么的,在data中是不需要导包的。
需要用转义符& lt;来代替<,

4.2使用

其实有了上面的基础,在这里学习就很简单了,虽然代码写的很吓人,各种转义符,但是其实就是一点,单列集合可以通过索引找到值,双列集合可以通过key找到对应的值。
有些朋友可能被SparseArray吓到了,其实他就是HashMap<Integer,?>的改良版。想了解的朋友可以看一下这个链接http://www.cnblogs.com/RGogoing/p/5095168.html

5.Resource

官方是这样介绍资源内容的:
我们希望你能在你的表达式中使用资源引用内容,因此你可以在你的表达式中使用资源和字符串格式化方法。
其实这里也很简单我们慢慢来看。

在表达式中引用资源↓
android:padding="@{large? (int)@dimen/largePadding : (int)@dimen/smallPadding}"
内联字符串格式:
android:text="@{@string/nameFormat(firstName, lastName)}"
同时,在string.xml文件中,这些只是占位符,s是字符串,d是整数
<string name="nameFormat">Full Name: %1$s:%2$s</string>
<string name="nameFormatWithAge">Hello %1$s %2$s, %3$d ages</string>
内联复数格式:这个我是真没用过,网上资料也少,不做解释···
android:text="@{@plurals/orange(orangeCount, orangeCount)}"
<plurals name="orange">
    <item quantity="one">Have an orange</item>
    <item quantity="other">Have %d oranges</item>
</plurals>

6.Observable

这个我说不真切,对他也心存疑惑,还有貌似现在已经支持双向绑定了。等我会了再来写····

7.ViewWithIds

这个之前已经说过了,这里就不说了。

android:id="@+id/firstName"===>binding.firstName.

8.ViewStub

ViewStub是Android布局优化的一种方式,是一个非常轻量的View,他和View.Gone,View.Visable类似,但又不一样,可以把它当成一个占位符,只会被加载一次,是一个非常不错的控件。
在这里,他和上面讲过的include在具体的实现上类似,因为它本身也少包裹着一层布局的。
但是奇怪的是

//这里标红,不能自动提示,虽然报错,但能运行,应该是studio支持的不好
if (!mBinding.viewStub.isInflated()) {      
mBinding.viewStub.getViewStub().inflate();}

9.Dynamic

重点来了。
RecyclerView + DataBinding.让我们把之前学习的运用过来,最好先自己试着写一下,再来看。
先说一下这个方法

setHasFixedSize(true);//我查了一下,貌似是说size固定的话,使用此方法,效率会提升

我们重点看一下Adapter

public static class UserHolder extends RecyclerView.ViewHolder {
    final UserItemBinding mBinding;
//通过构造将View视图和DataBinding进行绑定
    public UserHolder(View itemView) {
        super(itemView);
        mBinding = DataBindingUtil.bind(itemView);
    }
//其实这个方法的本质只是对外暴露UserItemBinding 用的
    public void bind(@NonNull User user) {
        mBinding.setUser(user);
    }
}

在看一下这俩方法

@Override
//通过打气筒获取到item_view,同时传递给ViewHolder
public UserHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
    View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.user_item, viewGroup, false);
    return new UserHolder(itemView);
}
@Override
//通过Binding对象将数据和视图进行绑定
public void onBindViewHolder(UserHolder holder, int position) {
    holder.bind(mUsers.get(position));}

我去,这也太简单太方便太简单了!!!
不过,平时我使用的都是陈宇明大神的https://github.com/CymChad/BaseRecyclerViewAdapterHelper
也是超级好用,超级方便。先学习,以后会有更简单的东西的··

10.Attribute setters

这个之前我们在3.1的时候也说过,可能我说的不是很明白,这里有例子,我把作者的话引入过来。
其实看这一块的时候,我一直惊呼,我靠太牛逼了。。。怪我没出息。
有了 Data Binding,即使属性没有在 declare-styleable
中定义,我们也可以通过 xml 进行赋值操作。 为了演示这个功能,我自定义了一个 View ,属性资源 [R.styleable.NameCard] 中只定义了一个 age
属性,其中 firstName 和lastName只有对应的两个 setter方法。只要有 setter方法就可以像下面代码一样赋值:

<com.liangfeizc.databindingsamples.attributesetters.UserView 
android:layout_width="match_parent" 
android:layout_height="wrap_content" 
android:paddingLeft="@dimen/largePadding" 
app:onClickListener="@{activity.clickListener}" 
app:firstName="@{@string/firstName}" 
app:lastName="@{@string/lastName}"
app:age="27"
 />

onClickListener
也是同样道理,只不过我们是在 Activity 中定义了一个 Listener

意思其实和我差不多,我这个标签没有这个属性,我可以自定义强塞给它这个属性,当它拿到属性之后怎么去处理,一般的话会引入一个注解,比如我们这里的@BindingAdapter({"imageUrl", "error"})
这是什么意思类?一开始我也不理解,后来看了11中的这个方法

@BindingAdapter("layout_height")
public static void setLayoutHeight(View view, float height) {    
    ViewGroup.LayoutParams params = view.getLayoutParams(); 
    params.height = (int) height;
    view.setLayoutParams(params);
}

那么意思再也明显不过了,我得到的这个值应该怎么去处理它。第一个参数对应的是这个View控件,而第二个就是我们给他 赋的值

11.Conversions,终于要完了

不好意思,这个我也没看懂···

··综上,也就辣么多了。其实我唯一能告诉大家的就是,DataBinding真的很简单也很方便使用,你需要做的仅仅是看一遍demo,不过最重要的还是千万别急躁,啥事都有个循序渐进的过程,尤其是学习。加油。

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

推荐阅读更多精彩内容