您的位置:首页 > 移动开发 > Android开发

Android MVVM之Databinding(二) 使用篇

2015-12-24 18:12 543 查看

1、环境需要:

1.Android 2.1 (API level 7+)
2.Gradle 1.5.0-alpha1
3.Android Studio 1.3


2、环境搭建

在build.gradle的android中加入如下字段,等待系统重新编译。

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


3、快速开始

1、编写布局布局文件

和传统的布局文件不同,databinding的布局文件的跟标签为
layout
,他有两个子标签,分别为
data
和原始布局标签,也就是说在原来的布局基础上多加了一层
layout
,然后里面又多了一个
data
标签。在写完布局文件之后别忘记MakeProject一下,以便系统自动生成对应的类,类名为布局文件的名字首字母大写。

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 配置变量,name字段为下面想要引用的类,type为全类名,
AS中快捷键ctrl+shift+alt+c -->
<data>
<variable
name="person"
type="com.znke.hellodatabinding.Person"/>
</data>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- 需要填充的字段用@{}表示 -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="25sp"
android:text="@{person.name}"
/>
<!-- 这里要转换一下,不然会引用int值所对应的R文件中的id -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="25sp"
android:text="@{String.valueOf(person.age)}"
/>
</LinearLayout>
</layout>


2、编写数据对象

一个简单POJO即可

public class Person {
public final String name;
public final int age;

public Person(String name, int age) {
this.name = name;
this.age = age;
}
}


3、在Acticity中进行绑定

在Acticity的onCreate(一个参数)方法里面进行绑定。

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//当编写完布局文件的时候,他会自动生成一个对应的类,名字为布局文件名称+Binding
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
Person person = new Person("liucl", 22);
//绑定
binding.setPerson(person);
}


* 注意:*编译过中程如果出现xxx.databingding不存在,那么就是你布局文件写错了。仔细检查,现在as还不支持语法提示。

运行正常如下:



成功了,就是这三步!!!

4、绑定点击事件

Databinding支持把事件绑定到对象中,使用方法和上面大同小异

1、编写事件对象

public class ClickEvent {

public void click(View v){
Toast.makeText(v.getContext(), "测试成功 \n Context对象为"
+ v.getContext().toString()
+ "\n View对象为"
+ v.toString(),
Toast.LENGTH_SHORT).show();
}

}


在这里我们吐司出v所在Context对象和View对象以及他所属的布局。

2、修改我们的布局文件

首先新建一个
variable
引入这个类。在
data
字段中加入

<variable
name="event"
type="com.znke.hellodatabinding.ClickEvent"/>


其实,我们可以使用
import
直接导入这个类,值得注意的是,这个区别于
java
import
关键字,
java
中这个是导入包,而这个是导入类。完整的
data
代码如下:

<data>
<import type="com.znke.hellodatabinding.Person"/>
<import type="com.znke.hellodatabinding.ClickEvent"/>
<variable
name="person"
type="Person"/>
<variable
name="event"
type="ClickEvent"/>
</data>


之后,我们在布局文件中加入一个
Button
,在
onClick
属性中引用这个类

<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="测试"
android:onClick="@{event.click}"/>


最后别忘记在Acticity中绑定!!!

...
binding.setEvent(new ClickEvent());
...


运行正常如下:



5、Include对象传递

Databinding支持include对象传递,在A布局里面的对象可以传递到他include进来的布局,

在A布局里定义号自定义命名空间。
xmlns:app="http://schemas.android.com/apk/res-auto"
下面要用到。

A布局里面的include标签

<include layout="@layout/include_click"
app:event="@{event}"/>


B布局代码

在B中也要引用一个传递过来的类,这个布局不用在Acticity中绑定。看过这个代码之后,你可能回想怎么不用
merge
优化呢,——暂时不支持

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

<data>
<variable name="event" type="com.znke.hellodatabinding.ClickEvent"/>
</data>

<!-- 暂不支持merge标签 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="测试" android:onClick="@{event.click}"/>
</LinearLayout>
</layout>


6、表达式符号

布局文件支持这些表达式,我直接引用谷歌文档

https://developer.android.com/tools/data-binding/guide.html

Mathematical  + - / * %
String  + 这个符号可能会引起引号冲突,需把文字放到资源文件
Logical  && ||
Binary & | ^
Unary + - ! ~
Shift >> >>> <<
Comparison == > < >= <=
instanceof
Grouping ()
Literals - character, String, numeric, null
Cast
Method calls
Field access
Array access []
Ternary operator ?:


7、绑定对象与视图,使他们能联动

通过更改对象,视图自动就会随之改变,这个功能实现View与model层逻辑代码的解耦和。

谷歌给出两种方法

Observable Objects

将你的POJO继承BaseObservable,这个类实现了Observable。可以实现POJO值改变,framework层会自动更新布局文件数据

private static class Person extends BaseObservable {
private String name;
private String age;
@Bindable
public String getName() {
return name;
}
@Bindable
public String getAge() {
return age;
}
public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.name);
}
public void setAge(String age) {
this.age = age;
notifyPropertyChanged(BR.age);
}
}


ObservableFields

其实他继承了BaseObservable这个类,在他的泛型中添上你的类型。同时

ObservableBoolean, ObservableByte, ObservableChar, ObservableShort, ObservableInt, ObservableLong, ObservableFloat, ObservableDouble,ObservableParcelable

也都是继承了BaseObservable。

public class Person {
public ObservableField<String> name = new ObservableField<>();
public ObservableInt age = new ObservableInt();
}


注:谷歌文档也给了一个Observable Collections,但我没试验成功,但是使用上面那个方法,是可以实现集合更改的。

通过上面的修改后,无论在那里改这个对象里面的值,相应的布局文件里面的引用都会随之改变。

8、抛弃你的findViewById()

有了
Databinding
再也不用谢冗长的findViewById()了,框架会为你自动生成的BR文件。

首先在我们的布局文件中,为我们两个
TextView
加上
id
,回到Acticity中的Binding对象,是不是多出了两个属性。

binding.tvText1.setText("");
binding.tvText2.setText("");


这样你就可以直接给他设置文本了,但是有一种更好的方法,直接
binding.setVariable(com.znke.hellodatabinding.BR.person,new Person());
就可以直接给布局文件中的变量赋值。

BR存储了布局中
data
标签中的
variable
,相当于R文件。

9、Attribute Setters(属性设置)

这东西就好像Button里面的onClick属性,然后给他在Acticity里面写一个对应的实现方法。他的强大之处就是它可以什么都向里面设置。不关是点击事件。他对于的实现方法只需要用一个注解声明就可以了,写在那里都可以,即使是一个没有使用的java文件。

通过一个Demo来说明,他有一个输入框,输入框输入文字,上面的
TextView
也会随之改变,这里用到了
属性设置
对象绑定


布局代码

<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="输入内容"
app:textwatcher="@{person}"/>


属性设置代码

public class BindingAdapter {

private static final String TAG = BindingAdapter.class.getSimpleName();

/**
* 添加上这个注解,方法为静态无返回值,
* 方法有两个参数,第一个是控件本身,第二个为传进来的对象
* 注意这个方法会被调用多次,其中会有对象为空的情况。So...
*
* @param e      控件本身
* @param person 传进来的对象
*/
@android.databinding.BindingAdapter({"app:textwatcher"})
public static void editTextWatcher(final EditText e,final Person person) {
if (person != null) {
e.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}

@Override
public void afterTextChanged(Editable s) {
person.name.set(s.toString());
e.setSelection(s.length());
}
});
}
}
}


BindingAdapter生命周期所在

View
所在
Activity
onCreate
方法之后。当然,自定义监听除外

12-21 11:39:51.289 3388-3388/? E/TAG: onFinishInflate:
12-21 11:39:51.295 3388-3388/? E/TAG: onCreate: null
12-21 11:39:51.331 3388-3388/? E/TAG: initAdapter:
12-21 11:39:51.331 3388-3388/? E/TAG: initManager:
12-21 11:39:51.333 3388-3388/? E/TAG: onAttachedToWindow:
12-21 11:39:51.338 3388-3388/? E/TAG: onMeasure:
12-21 11:39:51.406 3388-3388/? E/TAG: onLayout:
12-21 11:39:51.429 3388-3388/? E/TAG: onMeasure:
12-21 11:39:51.431 3388-3388/? E/TAG: onLayout:
12-21 11:39:51.433 3388-3388/? E/TAG: onDraw:
12-21 11:39:51.502 3388-3388/? E/TAG: onMeasure:


系列文章

Android MVVM(一) 介绍
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android mvvm databindin