DataBinding入門進階指南(一)
雜談
在程式設計領域,對於一名初學者而言,最開始的進階方式都是不斷重複的練習,然後在練習中遇到各種困難,同時也在這個過程裡積累了不少的經驗。
一般情況下,我們獲取的經驗可以有效的減少我們的失誤,也可以為我們預防掉許多“隱藏”的Bug。
但是,隨著我們能力的提升,我們逐漸的對於那些重複性非常高、而且意義並不大的程式碼產生了厭倦感。首當其衝的就是像 findViewById 這樣的程式碼!
大量的 findViewById 與全域性變數想必是許多初學者都會經歷的階段,不過學的東西越多,對於這類程式碼的接受力也就越低。所以許多人選擇用了 ButterKnife 去解決這個問題。
然鵝當 Kotlin 出現後, ButterKnife 也可以隨之拋棄了,這時候 DataBinding 的用處卻和 Kotlin 並不衝突,相反二者結合使用,反而會讓你有意想不到的、久違的、可圈可點的、眼前一亮的、拍手稱讚的體驗!
使用
使用 Data-Binding ,首先需要在 app moudle 下的 build.gradle 中新增:
android { ... dataBinding { enabled = true } ... }
然後就可以正常使用了,不過需要注意,最低支援的Android版本是4.0(反正幾乎沒有比這更低的android裝置了),gradle外掛版本是1.5.0 (都2018年了,android開發者們肯定不能用比這更低的版本了吧!)
接下來,舉個最簡單的栗子,我們建立一個 Cartoon 類:
class Cartoon(var name:String = "JOJO的奇妙冒險" , var series :String = "黃金之風", var leader : String = "喬魯諾·喬巴納", var feature : String = "黃金體驗") { }
然後新建一個Activity,在這個Activity的xml中的根佈局下,通過Alt+Enter快捷鍵建立databinding的佈局,同時,匯入 Cartoon 類:

image
這時候,編譯器會自動根據這個佈局生成相應的繫結類,這裡會生成一個 ActivityDataBindingBinding 的類 ,暫時先不用管,我們繼續在xml上工作,修改一下佈局樣式:

image
然後,在對應的Activity內對生成的 ActivityDataBindingBinding 類進行操作:
class DataBindingActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) //setContentView(R.layout.activity_data_binding) val bindingBinding : ActivityDataBindingBinding = DataBindingUtil.setContentView(this, R.layout.activity_data_binding) bindingBinding.cartoon = Cartoon() } }
由於Kotlin建立的Cartoon實體類已經給每個欄位都賦予了初始值,這裡不用再進行賦值,然後看一下效果:

image
如果你使用的是 items 去進行的繫結,例如Fragment、RecyclerView的adapter,可以使用 inflate() 的方法去繫結或者 DataBindingUtil 類,就像下面這樣
val listItemBinding = ListItemBinding.inflate(layoutInflater, viewGroup, false) // or val listItemBinding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false)
如果這時候你想使用字串拼接,可以在 string.xml 中建立,比如:
<string name="cartoon_name">動漫名:%s</string> <string name="cartoon_series">系列:%s</string> <string name="cartoon_leader">主角:</string> <string name="cartoon_bodyDouble">替身:</string>
使用的時候可以是這樣:
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="cartoon" type="com.test.project.testdatabinding.DataBinding.Cartoon"/> </data> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_gravity="center" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{@string/cartoon_name(cartoon.name)}"/> <TextView android:layout_gravity="center" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{@string/cartoon_series(cartoon.series)}"/> <TextView android:layout_gravity="center" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{@string/cartoon_leader + cartoon.leader}"/> <TextView android:layout_gravity="center" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{@string/cartoon_bodyDouble + cartoon.feature}"/> </LinearLayout> </layout>
效果如下:

image
至此,我們完成了與DataBinding的初次接觸!
可以看到,相較於往常的通過findViewById去獲取控制元件例項,然後給控制元件設定資料的方法,這樣顯然去掉了Activity內許多不必要的程式碼。
不過以上只是比較簡單的DataBinding用法,下面將會介紹DataBinding的其他功能,這樣才能應更復雜的需求。
集合的使用
<data> <import type="android.util.SparseArray"/> <import type="java.util.Map"/> <import type="java.util.List"/> <variable name="list" type="List<String>"/> <variable name="sparse" type="SparseArray<String>"/> <variable name="map" type="Map<String, String>"/> <variable name="index" type="int"/> <variable name="key" type="String"/> </data> … android:text="@{list[index]}" … android:text="@{sparse[index]}" … android:text="@{map[key]}"//這裡也可以使用 @{map.key}代替
點選事件
點選事件也是可以在xml中繫結的,在 DataBindingActivity 中新增如下方法:
fun doClick(view: View){ Toast.makeText(this, "點選測試", Toast.LENGTH_SHORT).show() }
不要忘了在括號中傳入View
然後再xml中寫一個button的點選事件
<Button android:text="DataBinding-點選測試" android:onClick="doClick" android:layout_width="wrap_content" android:layout_height="wrap_content" />
如果想通過點選事件傳入引數的話,可以通過下面這種方法:
<variable name="handler" type="com.test.project.testdatabinding.DataBinding.DataBindingActivity"/> <Button android:text="DataBinding-點選測試" android:onClick="@{() -> handler.doClick(cartoon.name)}" android:layout_width="wrap_content" android:layout_height="wrap_content" />
從xml中匯入 DataBindingActivity 後,再修改程式碼:
class DataBindingActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) //setContentView(R.layout.activity_data_binding) val bindingBinding : ActivityDataBindingBinding = DataBindingUtil.setContentView(this, R.layout.activity_data_binding) bindingBinding.cartoon = Cartoon() bindingBinding.handler = this } fun doClick(message: String){ Toast.makeText(this, message, Toast.LENGTH_SHORT).show() } }
點選效果如下:

image
如果有更加複雜的點選事件,可以參考官介紹中的,如帶View引數的:
class Presenter { fun onSaveClick(view: View, task: Task){} } android:onClick="@{(theView) -> presenter.onSaveClick(theView, task)}"
import 與 include
import
在xml中,可以通過匯入一些工具類進行簡單地操作,比如說匯入View類:
<data> <import type="android.view.View"/> </data>
這樣你就可以直接在xml中使用它的一些靜態方法或者變數,官方的例子中簡單地用法如下:
<TextView android:text="@{user.lastName}" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"/>
不過我覺得xml中不適合做太多邏輯判斷的操作,所以使用的時候應該考慮一下某些操作是否真的合適
include
如果你有在xml中使用到 include ,通過下面例子中的方法就行繫結:
<?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="cartoon" type="com.test.project.testdatabinding.DataBinding.Cartoon"/> </data> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <include layout="@layout/layout_test" bind:cartoon="@{cartoon}"/> </LinearLayout> </layout>
layout_test 佈局:
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="cartoon" type="com.test.project.testdatabinding.DataBinding.Cartoon"/> </data> <android.support.constraint.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:text="@{cartoon.name}" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </android.support.constraint.ConstraintLayout> </layout>
注意,要使用 bind 屬性,可別忘了下面的這行程式碼:
xmlns:bind="http://schemas.android.com/apk/res-auto"
暫歇
出於篇幅考慮,關於 DataBinding 的使用,暫且就講到這裡,關於它更詳盡的用法,後續再作介紹。