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 變量中,挺方便的!!