Android Data Binding 初探
Android Data Binding 进阶
Android Data Binding 配合BaseAdapter
学完 Data Binding 的基本使用方法后,我们来学学 Data Binding 的进阶。
Data Binding 最大的作用就是减少我们在 Activity 写更新和设置 UI 代码,有时候,View的更新过程需要一些简单的逻辑,如判断空,拼接字段等,因此,Android 的 Data Binding 还提供了一些简单的表达式供我们在 xml 布局文件中使用。
例子:
数据类
public class Person extends BaseObservable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Bindable
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.name);
}
@Bindable
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
notifyPropertyChanged(BR.age);
}
}
xml 布局文件
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="person"
type="com.johan.study.Person" />
</data>
<LinearLayout xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp"
tools:context="com.johan.study.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:textSize="16dp"
android:textColor="@android:color/holo_blue_light"
android:text="@{person.name}"
/>
</LinearLayout>
</layout>
Activity
public class MainActivity extends AppCompatActivity {
private Person person = new Person(null, 25);
private ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.setPerson(person);
}
}
如果看不懂,请看我博客 Android Data Binding 初探
三元表达式
更新 UI 最常用的逻辑应该是三元表达式了。我们来看看在 xml 布局文件中,三元表达式怎么使用:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:textSize="16dp"
android:textColor="@android:color/holo_blue_light"
android:text="@{person.name != null ? person.name : @string/app_name}"
/>
所有表达式都要写在“@{}”里面:
@{person.name != null ? person.name : @string/app_name}
是不是和我们在 Java 代码写的一样呢?毫无违和感,爽!!
另外,在“@{}”内使用资源,也是和普通的一样,只不过没有提示(这点真的不太好,容易写错)。
三元表达式我们还能这么用:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<!-- import 标签的作用是引入类,和 java 代码一样 -->
<!-- 因为在@{}中使用了View类,我们必须将包引入 -->
<import type="android.view.View" />
<variable
name="person"
type="com.johan.study.Person" />
</data>
<LinearLayout xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp"
tools:context="com.johan.study.MainActivity">
<!-- visibility 属性使用了三元表达式,如果person的name为null,就设置为View.GONE,和 java 代码一样 -->
<!-- 由于使用了 View 类,需要在data标签引入 View 类 -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:textSize="16dp"
android:textColor="@android:color/holo_blue_light"
android:text="@{person.name != null ? person.name : @string/app_name}"
android:visibility="@{person.name != null ? View.VISIBLE : View.GONE}"
/>
</LinearLayout>
</layout>
上面的例子中,如果没有 import View 类的话,编译器是没有提示,你就应该想到要 import 了。
空运算符
Data Binding 还提供一个空运算符“??”
<TextView
android:id="@+id/name_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:textSize="16dp"
android:textColor="@android:color/holo_blue_light"
android:text="@{person.name ?? @string/app_name}"
/>
其实
@{person.name ?? @string/app_name}
就等同于
@{person.name != null ? person.name : @string/app_name}
拼接
我们可以在“@{}”内拼接字符
<TextView
android:id="@+id/name_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:textSize="16dp"
android:textColor="@android:color/holo_blue_light"
android:text="@{@string/app_name + person.name}"
/>
这样就可以拼接字符了:
@{@string/app_name + person.name}
我们还能拼接“dimen”,在 dimens 资源文件定义的两个距离
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="space_1">15dp</dimen>
<dimen name="space_2">8dp</dimen>
</resources>
拼接 dimen 方式
<TextView
android:id="@+id/name_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@{@dimen/space_1 + @dimen/space_2}"
android:textSize="16dp"
android:textColor="@android:color/holo_blue_light"
android:text="@{person.name}"
/>
我们看
@{@dimen/space_1 + @dimen/space_2}
这方便我们计算好距离,然后再设置,不用重新定义新距离,这个功能很有用的。
使用方法
我们在 xml 中不仅可以使用类实例的方法,还能直接使用类的静态方法,就好像 java 一样。
类实例方法就是我们设置的监听事件。
我们来看看怎么使用类的静态方法:
定义静态方法:
public class Utils {
public static String formatName(String name) {
return "姓名:" + name;
}
}
xml 布局文件:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<!-- import 标签的作用是引入类,和 java 代码一样 -->
<!-- 因为在@{}中使用了Util类,我们必须将包引入 -->
<import type="com.johan.study.Utils" />
<variable
name="person"
type="com.johan.study.Person" />
</data>
<LinearLayout xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp"
tools:context="com.johan.study.MainActivity">
<!-- 使用 Utils.formatName 方法 -->
<!-- 由于使用了 Utils类,需要在data标签引入 Utils 类 -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:textSize="16dp"
android:textColor="@android:color/holo_blue_light"
android:text="@{Utils.formatName(person.name)}"
/>
</LinearLayout>
</layout>
其实和我们使用 java 代码很相似,很多东西我们不妨用 java 代码试试!
使用数组和集合
在 xml 布局中,我们能定义一个数组,List,Map,通过访问下标,设置属性值。
网上查的我都试了,不知道为什么 Android Studio 不支持定义数组和具体List,暂时还没想到会用到这个,先放着吧!!(知道的,麻烦留言告知,谢谢! ^_^)
其他表达式
数学 + - / * %
字符串连接 +
逻辑 && ||
二进制 & | ^
一元运算 + - ! ~
移位 >> >>> <<
比较 == > < >= <=
instanceof
分组 ()
null
Cast
方法调用
数据访问 []
三元运算 ?:
其他表达式自己慢慢探索,你可以的!! just try!!
include
这里再补充一个,我们布局的时候,可能会用到“include”标签来复用布局。如果“include”的 layout 也是一个 Data Binding 的布局文件,里面还绑定了数据,那我们怎么赋值给“include”的 layout 的变量呢?
还是一个例子说明
layout_include.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="person"
type="com.johan.study.Person" />
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/name_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:textSize="16dp"
android:textColor="@android:color/holo_blue_light"
android:text="@{person.name}"
/>
</LinearLayout>
</layout>
“include”的文件里面定义了person变量。
activity_main.xml 布局文件
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:binding="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="person"
type="com.johan.study.Person" />
<variable
name="handler"
type="com.johan.study.MainActivity.NameHandler" />
</data>
<LinearLayout xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp"
tools:context="com.johan.study.MainActivity">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:hint="输入姓名"
android:inputType="text"
android:textSize="16dp"
android:onTextChanged="@{handler.onTextChanged}"
/>
<!-- 在 xml 文件直接传值给 include 的 layout 中 -->
<include
layout="@layout/layout_include"
binding:person="@{person}"
/>
</LinearLayout>
</layout>
我们通过 xml 文件可以直接把值赋给“include”layout 的 person 变量中,挺方便的!!