欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android開發(fā)DataBinding基礎(chǔ)使用

 更新時間:2023年06月30日 11:53:58   作者:xuexiangjys  
這篇文章主要為大家介紹了Android開發(fā)DataBinding基礎(chǔ)使用實例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

1.前言

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

DataBinding的原理是通過編寫XML布局文件,在其中使用特定的標(biāo)簽和語法,將UI組件和數(shù)據(jù)模型連接起來。當(dāng)布局文件被加載時,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ā)者!

那么話不多說,讓我們直接直奔主題。接下來我將從實用性的角度,來逐一講解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進行創(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的變化而變化,這個時候你可能就需要使用MediatorLiveData,即合并LiveData。

這里我簡單利用MediatorLiveData實現(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) }

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

class CombineLiveDataState : DataBindingState() {
    val userName = MutableLiveData("小明")
    val userAge = MutableLiveData(20)
    val userInfo = combineLiveData(userName, userAge) { name, age -&gt;
        "${name}今年${age}歲了!"
    }
    fun onAgeChanged() {
        userAge.value = userAge.value?.plus(1)
    }
}

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

3.3 視圖綁定

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

  • 綁定Activity

使用DataBindingUtil.setContentView方法進行綁定。

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

使用DataBindingUtil.inflate方法進行綁定。

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
}
  • 綁定View

使用DataBindingUtil.bind方法進行綁定。

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

【??特別注意事項???】

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

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)進行賦值。
val mainState = ViewModelProvider(this).get(MainState::class.java)
binding.setVariable(BR.state, mainState)

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

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

4.基礎(chǔ)使用

4.1 點擊事件綁定

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表達式才生效(即@{})

使用@BindingAdapter進行控件自定義屬性綁定的時候,一定要使用 "@{}" 進行賦值,這一點非常重要?。?!

  • 頂級函數(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ù)進行綁定,requireAll=true,代表兩個參數(shù)都設(shè)置了才生效,默認是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()
}

【??特別注意事項???】

很多時候,很多新手在寫DataBinding的時候,經(jīng)常會漏掉"@{}",尤其是用數(shù)字和Boolean類型的值時。就比如我上面設(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}" />

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

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

  • 單例類+@JvmStatic注解
object TitleAdapter {
    @JvmStatic
    @BindingAdapter("customTitle2")
    fun setCustomTitle2(view: TextView, title: String) {
        view.text = "標(biāo)題4: $title"
    }
}

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

作用:在使用DataBinding的時候,對屬性值進行轉(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.這時候使用DataBinding的時候,??的app:age="@{state.user.age}"會編譯報錯,提示類型不匹配。

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

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

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

4.4 @{}中表達式使用

  • 常用運算符
  • 算術(shù) + - / * %
  • 字符串合并 +
  • 邏輯 && ||
  • 二元 & | ^
  • 一元 + - ! ~
  • 移位 >> >>> <<
  • 比較 == > < >= <=
  • 三元 ?:
  • Array 訪問 []
<TextView
    android:text="@{@string/app_name +  @string/app_name}"/>
<TextView 
    android:visibility="@{!state.user.phone.empty ? View.VISIBLE : View.GONE}"/>
  • 常用轉(zhuǎn)義字符
  • 空格: \&nbsp;
  • <小于號: \&lt;
  • \>大于號: \&gt;
  • &與號: \&amp;
<TextView 
    android:visibility="@{!state.user.phone.empty &amp;&amp; state.user.age > 5 ? View.VISIBLE : View.GONE}"/>
  • 資源使用

@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}" />
  • 集合

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

<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`]}" />
  • 引用類的靜態(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)}"/>
  • 空值合并運算符

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

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

等價于

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

4.5 include 和 ViewStub

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

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

  • 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引用布局的某個控件時,你需要給include設(shè)置資源id,然后通過它去訪問引用布局中的控件,就以??的例子為例,如果我想訪問布局中的TextView,我們可以這樣寫:

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

【??特別注意事項???】

這里需要注意的是,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。

  • 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>

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

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

最后

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

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

項目地址: https://github.com/xuexiangjys/DataBindingSample

以上就是Android開發(fā)DataBinding基礎(chǔ)使用的詳細內(nèi)容,更多關(guān)于Android DataBinding基礎(chǔ)的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Flutter 用自定義轉(zhuǎn)場動畫實現(xiàn)頁面切換

    Flutter 用自定義轉(zhuǎn)場動畫實現(xiàn)頁面切換

    本篇介紹了 fluro 導(dǎo)航到其他頁面的自定義轉(zhuǎn)場動畫實現(xiàn),F(xiàn)lutter本身提供了不少預(yù)定義的轉(zhuǎn)場動畫,可以通過 transitionBuilder 參數(shù)設(shè)計多種多樣的轉(zhuǎn)場動畫,也可以通過自定義的 AnimatedWidget實現(xiàn)個性化的轉(zhuǎn)場動畫效果。
    2021-06-06
  • 基于Android中手勢交互的實現(xiàn)方法

    基于Android中手勢交互的實現(xiàn)方法

    本篇文章是對Android中手勢交互的實現(xiàn)進行了詳細的分析介紹。需要的朋友參考下
    2013-05-05
  • Android 8.0中一些坑以及對應(yīng)的解決方法

    Android 8.0中一些坑以及對應(yīng)的解決方法

    這篇文章主要給大家介紹了關(guān)于Android 8.0中一些坑以及對應(yīng)的解決方法的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-09-09
  • 關(guān)于Touch Panel AA區(qū)要做外擴的原因解析

    關(guān)于Touch Panel AA區(qū)要做外擴的原因解析

    今天小編就為大家分享一篇關(guān)于Touch Panel AA區(qū)要做外擴的原因解析,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • ffmpeg實現(xiàn)去水印以及切分視頻demo

    ffmpeg實現(xiàn)去水印以及切分視頻demo

    這篇文章主要為大家介紹了ffmpeg實現(xiàn)去水印以及切分視頻demo,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-11-11
  • Android?Studio實現(xiàn)登錄界面功能

    Android?Studio實現(xiàn)登錄界面功能

    這篇文章主要為大家詳細介紹了Android?Studio實現(xiàn)登錄界面功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • Android開發(fā)之RadioGroup的簡單使用與監(jiān)聽示例

    Android開發(fā)之RadioGroup的簡單使用與監(jiān)聽示例

    這篇文章主要介紹了Android開發(fā)之RadioGroup的簡單使用與監(jiān)聽,結(jié)合實例形式分析了Android針對RadioGroup單選按鈕簡單實用技巧,需要的朋友可以參考下
    2017-07-07
  • Android開發(fā)之PopupWindow實現(xiàn)彈窗效果

    Android開發(fā)之PopupWindow實現(xiàn)彈窗效果

    這篇文章主要為大家詳細介紹了Android開發(fā)之PopupWindow實現(xiàn)彈窗效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-09-09
  • Android RecyclerView實現(xiàn)下拉列表功能

    Android RecyclerView實現(xiàn)下拉列表功能

    這篇文章主要介紹了Android RecyclerView實現(xiàn)下拉列表功能,下拉展開更多選項,具有一定的實用性,感興趣的小伙伴們可以參考一下
    2016-11-11
  • Android ViewDragHelper使用介紹

    Android ViewDragHelper使用介紹

    ViewDragHelper是support.v4下提供的用于處理拖拽滑動的輔助類。接下來通過本文給大家介紹Android ViewDragHelper使用,感興趣的朋友一起看看吧
    2017-08-08

最新評論