最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

DataBinding系列之基礎(chǔ)使用

2023-06-29 23:46 作者:xuexiangjys  | 我要投稿

1.前言

DataBinding, 又名數(shù)據(jù)綁定,是Android開發(fā)中非常重要的基礎(chǔ)技術(shù),它可以將UI組件和數(shù)據(jù)模型連接起來,使得在數(shù)據(jù)模型發(fā)生變化時(shí),UI組件自動更新,從而節(jié)省了大量的代碼和時(shí)間。

DataBinding的原理是通過編寫XML布局文件,在其中使用特定的標(biāo)簽和語法,將UI組件和數(shù)據(jù)模型連接起來。當(dāng)布局文件被加載時(shí),DataBinding會自動生成綁定代碼,從而將UI組件和數(shù)據(jù)模型關(guān)聯(lián)起來。

通過學(xué)習(xí)DataBinding基礎(chǔ)知識,可以讓你的代碼速度翻倍,提高開發(fā)效率和代碼質(zhì)量。因此,如果你希望在Android開發(fā)中獲得更高的成功率和更快的發(fā)展速度,那么請務(wù)必學(xué)習(xí)DataBinding技術(shù),掌握其基礎(chǔ)知識,讓自己成為一名高效率的Android開發(fā)者!

那么話不多說,讓我們直接直奔主題。接下來我將從實(shí)用性的角度,來逐一講解DataBinding的基礎(chǔ)使用,文章末尾會給出示例代碼的鏈接地址,希望能給你帶來啟發(fā)。

2.準(zhǔn)備工作

2.1 啟用

1.DataBinding啟用

android?{
????dataBinding?{
????????enabled?=?true
????}
}

2.ViewBinding啟用

android?{
????buildFeatures?{
????????viewBinding?true
????}?
}

2.2 快捷方式

在你的布局中找到最外層的布局,將光標(biāo)放在如圖位置。

  • Windows 請按快捷鍵 Alt + 回車

  • Mac 請按快捷鍵 option + 回車

3.DataBinding綁定

3.1 數(shù)據(jù)類型

通常我們在DataBinding中綁定的數(shù)據(jù)類型是ViewModel或者是AndroidViewModel,它倆都是生命周期可感知的,唯一的區(qū)別是AndroidViewModel可以獲取到應(yīng)用的上下文Application。

3.2 數(shù)據(jù)創(chuàng)建

ViewModel的創(chuàng)建通常是通過ViewModelProvider進(jìn)行創(chuàng)建和獲取。

ViewModelProvider(this).get(Xxx::class.java)

而在ViewModel中,通常使用MutableLiveData作為可變UI響應(yīng)數(shù)據(jù)類型。相比較LiveData而言,它開放了修改值的接口,下面是一個ViewModel的簡單例子:

class?RecyclerViewRefreshState(application:?Application)?:?AndroidViewModel(application)?{

????val?title?=?MutableLiveData("RecyclerView的刷新和加載更多演示")
????val?isLoading?=?MutableLiveData(false)
????val?sampleData?=?MutableLiveData<List<SimpleItem>>(arrayListOf())
????val?loadState?=?MutableLiveData(LoadState.DEFAULT)
????val?layoutStatus?=?MutableLiveData(Status.DEFAULT)
}

當(dāng)然了,如果你有一個LiveData會隨著一個或多個LiveData的變化而變化,這個時(shí)候你可能就需要使用MediatorLiveData,即合并LiveData。

這里我簡單利用MediatorLiveData實(shí)現(xiàn)一個組合的LiveData--CombinedLiveData。

open?class?CombinedLiveData<T>(vararg?liveData:?LiveData<*>,?block:?()?->?T)?:
????MediatorLiveData<T>()?{
????init?{
????????value?=?block()
????????liveData.forEach?{
????????????addSource(it)?{
????????????????val?newValue?=?block()
????????????????if?(value?!=?newValue)?{
????????????????????value?=?newValue
????????????????}
????????????}
????????}
????}
}

fun?<R,?T1,?T2>?combineLiveData(
????liveData1:?LiveData<T1>,
????liveData2:?LiveData<T2>,
????block:?(T1?,?T2?)?->?R
)
?=?CombinedLiveData(liveData1,?liveData2)?{?block(liveData1.value,?liveData2.value)?}

這個時(shí)候,我們就可以通過combineLiveData方法將兩個LiveData組合起來,形成一個新的LiveData。下面我簡單給出一個示例代碼:

class?CombineLiveDataState?:?DataBindingState()?{
????val?userName?=?MutableLiveData("小明")
????val?userAge?=?MutableLiveData(20)
????val?userInfo?=?combineLiveData(userName,?userAge)?{?name,?age?->
????????"${name}今年${age}歲了!"
????}

????fun?onAgeChanged()?{
????????userAge.value?=?userAge.value?.plus(1)
????}
}

這里變化了userAge的值后,userInfo也會隨著一起變化。

3.3 視圖綁定

一般我們使用DataBindingUtil進(jìn)行視圖綁定操作。綁定操作我們可分為:綁定Activity、綁定Fragment和綁定View。

  1. 綁定Activity

使用DataBindingUtil.setContentView方法進(jìn)行綁定。

fun?<DataBinding?:?ViewDataBinding>?bindActivity(
????activity:?ComponentActivity,
????layoutId:?Int
)
:?DataBinding?=?DataBindingUtil.setContentView<DataBinding>(activity,?layoutId).apply?{
????lifecycleOwner?=?activity
}

  1. 綁定Fragment

使用DataBindingUtil.inflate方法進(jìn)行綁定。

fun?<DataBinding?:?ViewDataBinding>?bindFragment(
????fragment:?Fragment,
????inflater:?LayoutInflater,
????layoutId:?Int,
????parent:?ViewGroup??=?null,
????attachToParent:?Boolean?=?false
)
:?DataBinding?=?DataBindingUtil.inflate<DataBinding>(inflater,?layoutId,?parent,?attachToParent).apply?{
????lifecycleOwner?=?fragment.viewLifecycleOwner
}

  1. 綁定View

使用DataBindingUtil.bind方法進(jìn)行綁定。

fun?<DataBinding?:?ViewDataBinding>?bindView(
????view:?View,
????viewLifecycleOwner:?LifecycleOwner,
)
:?DataBinding?=?DataBindingUtil.bind<DataBinding>(view).apply?{
????lifecycleOwner?=?viewLifecycleOwner
}

【??特別注意事項(xiàng)???】

DataBinding綁定的時(shí)候,一定要給ViewDataBinding賦值LifecycleOwner, 否則ViewModel中的LiveData發(fā)生數(shù)據(jù)改變后,則不會通知UI組件進(jìn)行頁面更新。

3.4 數(shù)據(jù)綁定

對ViewModel的綁定有兩種寫法。

  • 直接使用ViewDataBinding.variableId = xxx直接賦值。

val?mainState?=?ViewModelProvider(this).get(MainState::class.java)
activityMainbinding.state?=?mainState

  • 使用ViewDataBinding.setVariable(int variableId, @Nullable Object value)進(jìn)行賦值。

val?mainState?=?ViewModelProvider(this).get(MainState::class.java)
binding.setVariable(BR.state,?mainState)

這兩者的唯一區(qū)別在于,第一種需要知道ViewDataBinding的具體類型,而第二種是ViewDataBinding自身的方法,無需知道ViewDataBinding的具體類型。

一般來說在框架中使用到泛型未知ViewDataBinding具體類型的時(shí)候,都會使用第二種方式進(jìn)行綁定,可以說第二種方式更通用一些。

4.基礎(chǔ)使用

4.1 點(diǎn)擊事件綁定

1.無參響應(yīng)函數(shù):

fun?onIncrement()?{
????//?方法體
}
android:onClick="@{()?->?state.onIncrement()}"

2.接口變量響應(yīng)函數(shù)

注意,這里變量的類型應(yīng)該是View.OnClickListener接口。

val?onClickDecrement?=?View.OnClickListener?{
????//?方法體
}
android:onClick="@{state.onClickDecrement}"

3.有參響應(yīng)函數(shù)

fun?onReset(view:?View)?{
????//?方法體
}
//?第一種寫法
android:onClick="@{(view)?->?state.onReset(view)}"?

//?第二種寫法
android:onClick="@{state::onReset}"

4.2 @BindingAdapter自定義屬性

所有注解的功能都是基于XML屬性值為DataBinding表達(dá)式才生效(即@{})

使用@BindingAdapter進(jìn)行控件自定義屬性綁定的時(shí)候,一定要使用 "@{}" 進(jìn)行賦值,這一點(diǎn)非常重要?。?!

  1. 頂級函數(shù)實(shí)現(xiàn)

//?Kotlin拓展函數(shù)式寫法,?推薦使用
@BindingAdapter("customTitle")
fun?TextView.setCustomTitle(title:?String)?{
????text?=?"標(biāo)題1:?$title"
}

//?第一個參數(shù)必須是view的子類
@BindingAdapter("customTitle1")
fun?setCustomTitle1(view:?TextView,?title:?String)?{
????view.text?=?"標(biāo)題2:?$title"
}

//?多個參數(shù)進(jìn)行綁定,requireAll=true,代表兩個參數(shù)都設(shè)置了才生效,默認(rèn)是true.
//?如果requireAll為false,?你沒有填寫的屬性值將為null.?所以需要做非空判斷.
@BindingAdapter(value?=?["customTitle",?"customSize"],?requireAll?=?true)
fun?TextView.setTextContent(title:?String,?size:?Int)?{
????text?=?"標(biāo)題3:?$title"
????textSize?=?size.toFloat()
}

【??特別注意事項(xiàng)???】

很多時(shí)候,很多新手在寫DataBinding的時(shí)候,經(jīng)常會漏掉"@{}",尤其是用數(shù)字和Boolean類型的值時(shí)。就比如我上面設(shè)置的customSize屬性,類型值是Int型,正確的寫法應(yīng)該是下面這樣:

  • 正確的寫法

<TextView
????style="@style/TextStyle.Title"
????android:layout_marginTop="16dp"
????app:customSize="@{25}"
????app:customTitle="@{state.title}"?/>

  • 常見錯誤的寫法

<TextView
????style="@style/TextStyle.Title"
????android:layout_marginTop="16dp"
????app:customSize="25"
????app:customTitle="@{state.title}"?/>

上述錯誤的寫法,運(yùn)行后編譯器會報(bào)錯AAPT: error: attribute customSize (aka com.xuexiang.databindingsample:customSize) not found.。

所以當(dāng)我們寫DataBinding的時(shí)候,如果出現(xiàn)AAPT: error: attribute xxx (aka com.aa.bb:xxx) not found.,十有八九是你賦值漏掉了"@{}"。

  1. 單例類+@JvmStatic注解

object?TitleAdapter?{
????@JvmStatic
????@BindingAdapter("customTitle2")
????fun?setCustomTitle2(view:?TextView,?title:?String)?{
????????view.text?=?"標(biāo)題4:?$title"
????}
}

4.3 @BindingConversion自定義類型轉(zhuǎn)換

作用:在使用DataBinding的時(shí)候,對屬性值進(jìn)行轉(zhuǎn)換,以匹配對應(yīng)的屬性。 定義:方法必須為公共靜態(tài)(public static)方法,且有且只能有1個參數(shù)。

下面我給一個簡單的例子:

1.對于User類,age的類型是Int。

data?class?User(
????val?name:?String,
????val?gender:?String??=?"男",
????val?age:?Int?=?10,
????val?phone:?String??=?"13124765438",
????val?address:?String??=?null
)

2.使用@BindingAdapter定義了age的類型卻是String。

@BindingAdapter(value?=?["name",?"age"],?requireAll?=?true)
fun?TextView.setUserInfo(name:?String,?age:?String)?{
????text?=?"${name}今年${age}歲"
}

3.這時(shí)候使用DataBinding的時(shí)候,??的app:age="@{state.user.age}"會編譯報(bào)錯,提示類型不匹配。

<TextView
????style="@style/TextStyle.Title"
????android:layout_marginTop="16dp"
????app:name="@{state.user.name}"
????app:age="@{state.user.age}"/>

4.這個時(shí)候,我們就可以使用@BindingConversion自定義類型轉(zhuǎn)換: Int -> String, 這樣??的代碼就不會編譯出錯了。

@BindingConversion
fun?int2string(integer:?Int)?=?integer.toString()

4.4 @{}中表達(dá)式使用

  1. 常用運(yùn)算符

  • 算術(shù) + - / * %

  • 字符串合并 +

  • 邏輯 && ||

  • 二元 & | ^

  • 一元 + - ! ~

  • 移位 >> >>> <<

  • 比較 == > < >= <=

  • 三元 ?:

  • Array 訪問 []

<TextView
????android:text="@{@string/app_name?+??@string/app_name}"/>

<TextView?
????android:visibility="@{!state.user.phone.empty???View.VISIBLE?:?View.GONE}"/>

  1. 常用轉(zhuǎn)義字符

  • 空格: ?&nbsp;

  • <小于號: ?&lt;

  • >大于號: ?&gt;

  • &與號: &amp;

<TextView?
????android:visibility="@{!state.user.phone.empty?&amp;&amp;?state.user.age?>?5???View.VISIBLE?:?View.GONE}"/>

  1. 資源使用

@string @color @drawable @dimen @array

<TextView
????style="@style/TextStyle.Content"
????android:text="@{@string/user_format(state.user.name,?state.user.gender)}"
????android:textColor="@{@color/toast_error_color}"
????android:textSize="@{@dimen/xui_config_size_content_text_phone}"?/>

  1. 集合

集合不屬于java.lang*下, 需要導(dǎo)入全路徑。集合使用[]進(jìn)行訪問。

<data>
????<import?type="java.util.List"/>
????<import?type="android.util.SparseArray"/>
????<import?type="java.util.Map"/>
????<variable?name="list"?type="List&lt;String>"/>
????<variable?name="sparse"?type="SparseArray&lt;String>"/>
????<variable?name="map"?type="Map&lt;String,?String>"/>
</data>
<TextView
????android:text="@{`key:?key1,?value:`?+?map[`key1`]}"?/>

  1. 引用類的靜態(tài)方法

kotlin中定義靜態(tài)方法,一定要在方法上加上@JvmStatic,否則將無法成功引用。

(1) 定義方法

object?AppUtils?{

????@JvmStatic
????fun?getAppInfo(context:?Context?)?=
????????context?.let?{
????????????"packageName:?${it.packageName},?\nversionName:?${
????????????????it.packageManager.getPackageInfo(
????????????????????it.packageName,
????????????????????0
????????????????).versionName
????????????}
"

????????}
}

(2) 導(dǎo)入方法所在類路徑

<import?type="com.xuexiang.databindingsample.utils.AppUtils"/>

(3) 引用方法

<TextView
????android:text="@{AppUtils.getAppInfo(context)}"/>

  1. 空值合并運(yùn)算符

空值合并運(yùn)算符 ?? 會取第一個不為 null 的值作為返回值。

<TextView
????android:text="@{`地址:`?+?(state.user.address????`默認(rèn)地址`)}"/>

等價(jià)于

<TextView
????android:text="@{state.user.address?!=?null????state.user.address?:?`默認(rèn)地址`)}"/>

4.5 include 和 ViewStub

在主布局文件中將相應(yīng)的變量傳遞給 include 布局,需使用自定義的 bind 命名空間將變量傳遞給 (include/ViewStub), 從而使兩個布局文件之間共享同一個變量。

例如,在include中定義的變量id是:, 那么就使用 app:user="@{state.user}" 來綁定數(shù)據(jù),與variable定義的name保持一致。

  1. include

<include
????android:id="@+id/include_layout"
????layout="@layout/include_user_info"
????app:user="@{state.user}"?/>

<layout?xmlns:android="http://schemas.android.com/apk/res/android">

????<data>
????????<variable
????????????name="user"
????????????type="com.xuexiang.databindingsample.fragment.basic.model.User"?/>


????</data>

????<LinearLayout
????????android:layout_width="match_parent"
????????android:layout_height="wrap_content"
????????android:layout_marginVertical="16dp"
????????android:orientation="vertical">

????????
????????<TextView
????????????android:id="@+id/tv_title"
????????????style="@style/TextStyle.Content"
????????????android:userInfo="@{user}"?/>


????</LinearLayout>
</layout>

如果你想在頁面中獲取include引用布局的某個控件時(shí),你需要給include設(shè)置資源id,然后通過它去訪問引用布局中的控件,就以??的例子為例,如果我想訪問布局中的TextView,我們可以這樣寫:

binding?.includeLayout?.tvTitle?.text?=?"用戶信息"

【??特別注意事項(xiàng)???】

這里需要注意的是,include標(biāo)簽,如果設(shè)置了layout_widthlayout_height這兩個屬性,那么布局就是由include外層設(shè)置的layout屬性生效,內(nèi)層屬性不生效。

如果include標(biāo)簽沒有設(shè)置layout_widthlayout_height這兩個屬性,那么就是由include引用的布局內(nèi)層設(shè)置的layout屬性生效。

舉個例子,如果把??設(shè)置的include改成下面這樣:

<include
????layout="@layout/include_user_info"
????android:layout_width="match_parent"
????android:layout_height="wrap_content"
????android:layout_marginTop="24dp"
????app:user="@{state.user}"?/>

那么@layout/include_user_info加載的布局,距離上部的距離就是24dp,而不是16dp。

  1. ViewStub

<ViewStub
????android:id="@+id/user_info"
????android:layout_width="match_parent"
????android:layout_height="wrap_content"
????android:layout_marginTop="16dp"
????android:layout="@layout/viewstub_user_info"
????app:info="@{state.user}"?/>

<layout?xmlns:android="http://schemas.android.com/apk/res/android">

????<data>
????????<variable
????????????name="info"
????????????type="com.xuexiang.databindingsample.fragment.basic.model.User"?/>


????</data>

????<TextView
????????style="@style/TextStyle.Content"
????????android:userInfo="@{info}"?/>

</layout>

因?yàn)閂iewStub功能是延遲加載引用的布局,當(dāng)我們需要讓其進(jìn)行加載的時(shí)候,我們需要通過ViewStub的資源id獲取到ViewStub,然后進(jìn)行inflate,示例代碼如下:

binding?.userInfo?.viewStub?.inflate()

最后

以上就是本次DataBinding基礎(chǔ)使用的全部內(nèi)容,后面我還會分享DataBinding的進(jìn)階使用教程,感興趣的小伙伴可以點(diǎn)擊頭像關(guān)注我哦~

本文的全部源碼我都放在了github上, 感興趣的小伙伴可以下下來研究和學(xué)習(xí)。

項(xiàng)目地址: https://github.com/xuexiangjys/DataBindingSample

我是xuexiangjys,一枚熱愛學(xué)習(xí),愛好編程,勤于思考,致力于Android架構(gòu)研究以及開源項(xiàng)目經(jīng)驗(yàn)分享的技術(shù)up主。獲取更多資訊,歡迎微信搜索公眾號:【我的Android開源之旅】


DataBinding系列之基礎(chǔ)使用的評論 (共 條)

分享到微博請遵守國家法律
保康县| 清远市| 通城县| 克什克腾旗| 社旗县| 达拉特旗| 青岛市| 灵石县| 南昌县| 利津县| 呼玛县| 友谊县| 肇东市| 金昌市| 峨山| 施甸县| 固始县| 罗源县| 内江市| 遂昌县| 沿河| 娄底市| 兴和县| 马龙县| 长泰县| 五峰| 麻城市| 门头沟区| 永福县| 定州市| 岑巩县| 鄂尔多斯市| 天峻县| 遂昌县| 嵊州市| 南江县| 棋牌| 建宁县| 六盘水市| 乌拉特后旗| 宜阳县|