Android架構元件-DataBinding的使用
什麼是DataBinding
Data Binding,顧名思義,資料繫結,是Google對MVVM在Android上的一種實現,可以直接繫結資料到xml中,並實現自動重新整理。現在最新的版本還支援雙向繫結,儘管使用場景不是那麼多。
Data Binding可以提升開發效率(節省很多以往需要手寫的java程式碼),效能高(甚至超越手寫程式碼),功能強(強大的表示式支援)。
用途
去掉Activities & Fragments內的大部分UI程式碼(setOnClickListener, setText, findViewById, etc.)
XML變成UI的唯一真實來源
減少定義view id的主要用途(資料繫結直接發生在xml)
優勢
- UI程式碼放到了xml中,佈局和資料更緊密
- 效能超過手寫程式碼
- 保證執行在主執行緒
劣勢
- IDE支援還不那麼完善(提示、表示式)
- 報錯資訊不那麼直接
- 重構支援不好(xml中進行重構,java程式碼不會自動修改)
DataBinding的使用
Android Studio 的相容版本,需要 1.3 及以上的版本.
在Android Studio上使用,需要在module級別的build.gradle上新增對DataBinding的支援:
android {
...
dataBinding {
enabled = true
}
}
-
資料繫結佈局檔案XML
資料繫結的xml和我們以前經常寫的xml稍有不同,從佈局的跟標記開始,依次是根佈局layout,資料元素data節點,檢視元素,例如:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
>
<data>
<variable name="user" type="com.example.User"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.lastName}"/>
</LinearLayout>
</layout>
資料中的使用者變數描述此佈局中可能使用的屬性:
<variable name="user" type="com.example.User"/>
佈局中的表示式使用 "@{}" 語法在屬性中寫入,在這裡,TextView 的文字設定為使用者 FirstName 屬性:
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}"/>
-
資料物件User:
class UserModel {
var lastName: String? = null
var firstName: String? = null
···
}
-
資料繫結
生成例項,會有一定的規則,layout通過檔名生成,View通過id生成,通過dataBinding.setVariable(Variable variable);來實現資料的繫結。
預設情況下,繫結類將根據 layout 檔案的名稱生成,首字母大寫的命名規範,並新增 "Binding" 字尾,上述的佈局檔案是main_activity.xml,所以生成類是 MainActivityBinding, 該類將佈局屬性(例如 User 變數)的所有繫結儲存到佈局檢視中,並知道如何為繫結表示式賦值,建立最簡單的方法是在 inflating 時繫結,如下:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MainActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.main_activity);
User user = new User("Test", "User");
binding.setUser(user);
}
如果你是在 RecyclerView adapter 中使用 Data Binding 時,你可能使用:
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): AdapterBindingViewHolder<*> {
var binding: ViewDataBinding = DataBindingUtil.inflate(mLayoutInflater, R.layout.book_recycle_item, parent, false)
return AdapterBindingViewHolder(binding)
}
通過自定義類名,這樣就可以避開上面的規則
<data class="CustomBinding"></data> //在app_package/databinding下生成CustomBinding;
<data class=".CustomBinding"></data> //在app_package下生成CustomBinding;
<data class="com.example.CustomBinding"></data> // 明確指定包名和類名。
-
事件處理
資料繫結允許你編寫表示式處理,如 onClick 事件
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{() -> viewModel.onClickBindalbeTest()}"
android:text="click bindalbe test"
/>
可以使用多個引數的 Lambda 表示式:
public class Presenter {
public void onSaveClick(View view, Task task){}
}
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onCheckedChanged="@{(cb, isChecked) -> presenter.completeChanged(task, isChecked)}" />
還可以使用三元表示式:
android:onClick="@{(v) -> v.isVisible() ? doSomething() : void}"
-
XML data的使用
可以在資料元素內使用零個或多個匯入元素。這些可以參考在你的佈局檔案的類,就像在 java:
<data>
<import type="android.view.View"/>
</data>
現在,檢視可以在繫結表示式中使用:
<TextView
android:text="@{user.lastName}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"/>
當有類名衝突時,其中一個類可以定義一個別名為“alias:”,如下:
<import type="android.view.View"/>
<import type="com.example.real.estate.View"
alias="Vista"/>
在表示式中引用靜態欄位和方法時也可以使用匯入型別:
<data>
<import type="com.example.MyStringUtils"/>
<variable name="user" type="com.example.User"/>
</data>
…
<TextView
android:text="@{MyStringUtils.capitalize(user.lastName)}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
可以在資料元素內使用任意數量的變數元素。每個變數元素描述可以在佈局檔案中用於繫結表示式中的佈局的屬性:
<data>
<import type="android.graphics.drawable.Drawable"/>
<variable name="user" type="com.example.User"/>
<variable name="image" type="Drawable"/>
<variable name="note" type="String"/>
</data>
還可以自定義繫結類名
通過調整資料元素的類屬性可以將繫結類重新命名或放置在不同的包中。例如:
<data class="ContactItem">
...
</data>
這個生成繫結類中的模組封裝在資料繫結包 ContactItem,如果類產生在不同的包中的模組封裝內,它可能會加 ".",如下:
<data class=".ContactItem">
...
</data>
在這種情況下,ContactItem 直接在模組封裝生成,如果提供完整的包,任何包可以使用:
<data class="com.example.ContactItem">
...
</data>
通過使用應用程式名稱空間和屬性中的變數名,可以將變數從包含佈局中傳遞到包含佈局中:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
<variable name="user" type="com.example.User"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/name"
bind:user="@{user}"/>
</LinearLayout>
</layout>
-
表示式
支援的運算子:
<ul>
<li>數學運算子: + - / * %</li>
<li>字串拼接: +</li>
<li>邏輯運算子: && ||</li>
<li>二進位制: & | ^</li>
<li>一元運算子: +</li>
<li>位運算子: >> >>> <<</li>
<li>比較: == > < >= <=</li>
<li>instanceof</li>
<li>()</li>
<li>資料型別: character, String, numeric, null</li>
<li>型別轉換(ClassCast)</li>
<li>方法回撥(Method calls)</li>
<li>資料屬性</li>
<li>陣列:[]</li>
<li>三元操作符:?</li>
</ul>
使用如下:
android:text="@{String.valueOf(index + 1)}"
android:visibility="@{age < 13 ? View.GONE : View.VISIBLE}"
android:transitionName='@{"image_" + id}'
android:text="@{user.displayName ?? user.lastName}"
...
可以使用正常語法的表示式訪問資源:
<string name="nameFormat">%s - %s</string>
android:text="@{@string/nameFormat(user.displayName , user.lastName)}"
也可以直接資料處理
android:text="@{Integer.toString(user.age)}"
-
Observable Objects
目前所提供的ObservableField有:
Observable型別 | 對應原型別 |
---|---|
ObservableArrayList | ArrayList |
ObservableArrayMap | ArrayMap |
ObservableBoolean | boolean |
ObservableByte | byte |
ObservableChar | char |
ObservableFloat | float |
ObservableDouble | double |
ObservableLong | long |
ObservableInt | int |
ObservableParcelable<T extends Parcelable> | <T extends Parcelable> |
ObservableField<T> | <T> |
Observable是提供新增移除監聽的一個java介面,DataBinding基於此介面提供了一個基礎類BaseObserable,我們可以這樣使用它,通過Bindale註解繫結一個getter,當data屬性發生改變在setter中發出通知,這樣就實現了響應
/**
* 繼承BaseObservable
* set方法notifyPropertyChanged
* get方法@Bindable
*/
class BindalbeTestModel: BaseObservable() {
var testStr: String? = null
set(value) {
field = value
notifyPropertyChanged(com.ghp.demo.databindingdemoproject.BR.testStr)
}
@Bindable
get() {
return field?:""
}
}
根據google為我們提供了一些Obserable類,還可以這樣:
public static class UserModel {
public final ObservableField<String> firstName =
new ObservableField<>();
public final ObservableField<String> lastName =
new ObservableField<>();
public final ObservableInt age = new ObservableInt();
}
看這樣的UserModel會不會覺得煩瑣,其實還可以這樣
class UserModel {
var firstName: String? = null
var userAge: Int = 0
var lastName: String? = null
}
var user = ObservableField<UserModel>()
/**
* ObservableField可以包裹變數非Observable的model
* model初始化後,更改值,必須要notifyChange重新整理UI
*/
fun onclickObservableFieldUser() {
user.get().firstName = "ghp"
user.notifyChange()
}
ObservableArrayMap:
ObservableArrayMap<String, Object> user = new ObservableArrayMap<>();
user.put("firstName", "Google");
user.put("lastName", "Inc.");
user.put("age", 17);
在xml中使用:
<data>
<import type="android.databinding.ObservableMap"/>
<variable name="user" type="ObservableMap<String, Object>"/>
</data>
…
<TextView
android:text='@{user["lastName"]}'
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:text='@{String.valueOf(1 + (Integer)user["age"])}'
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
ObservableArrayList:
ObservableArrayList<Object> user = new ObservableArrayList<>();
user.add("Google");
user.add("Inc.");
user.add(17);
xml使用:
<data>
<import type="android.databinding.ObservableList"/>
<import type="com.example.my.app.Fields"/>
<variable name="user" type="ObservableList<Object>"/>
</data>
…
<TextView
android:text='@{user[Fields.LAST_NAME]}'
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:text='@{String.valueOf(1 + (Integer)user[Fields.AGE])}'
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
參考:
DataBinding使用全面詳解
Android DataBinding 詳解
從零開始的Android新專案7 - Data Binding入門篇
相關文章
- Android架構元件Room的使用Android架構元件OOM
- Android 架構選型 (MVP+DataBinding)Android架構MVP
- Android官方架構元件DataBinding雙向繫結篇: 觀察者模式的殊途同歸Android架構元件模式
- MVVM架構篇之DataBinding(-)MVVM架構
- Android 元件化架構概要Android元件化架構
- Android MVVM元件化架構方案AndroidMVVM元件化架構
- 《Android元件化架構》上市了Android元件化架構
- Android新元件架構——LifecylceAndroid元件架構
- Android架構元件WorkManager詳解Android架構元件
- Android 架構元件的最新進展 (上篇)Android架構元件
- Android Jetpack(2):DataBinding的基本使用AndroidJetpack
- 剖析 Android 架構元件之 ViewModelAndroid架構元件View
- Android 官方架構元件(一)——LifecycleAndroid架構元件
- Android 官方架構元件(二)——LiveDataAndroid架構元件LiveData
- Android 官方架構元件(三)——ViewModelAndroid架構元件View
- Android Jetpack 架構元件之 NavigationAndroidJetpack架構元件Navigation
- Android Jetpack架構元件(七)之WorkManagerAndroidJetpack架構元件
- Android 官方架構元件之 LifecycleAndroid架構元件
- 改造 Android 官方架構元件 ViewModelAndroid架構元件View
- 初學 Android 架構元件之 LifecycleAndroid架構元件
- 初學 Android 架構元件之 ViewModelAndroid架構元件View
- [Android元件化]AAB外掛化架構Android元件化架構
- Android 架構元件 - Lifycycle, LiveData, ViewModelAndroid架構元件LiveDataView
- Android 架構元件 - 讓天下沒有難做的 AppAndroid架構元件APP
- Android官方架構元件Navigation:大巧不工的Fragment管理框架Android架構元件NavigationFragment框架
- Android架構元件穩定版正式釋出Android架構元件
- Jetpack架構元件學習(1)——LifeCycle的使用Jetpack架構元件
- Android:DataBinding的一二事Android
- Android開發教程-使用DataBinding(六)RecyclerViewAdapter中的使用AndroidViewAPT
- Android Jetpack - DataBindingAndroidJetpack
- Android 控制元件架構與自定義控制元件詳解Android控制元件架構
- Android 架構設計:MVC、MVP、MVVM和元件化Android架構MVCMVPMVVM元件化
- 正式釋出 Android 架構元件 1.0 穩定版Android架構元件
- Android Studio: Kotlin使用DataBinding異常AndroidKotlin
- Android官方架構元件Lifecycle:生命週期元件詳解&原理分析Android架構元件
- Android系統架構-----Android的系統體系架構Android架構
- RabbitMQ 元件和架構MQ元件架構
- 元件化 構架思路元件化