DataBinding-使用篇

概念

DataBind 就是 基于apt技術类早,幫我們生成了一些模板代碼锌唾,這些模板代碼大概解決了如下操作:

  1. 控件變量的聲明灼伤,類似如下:
 @NonNull
 public final TextView tv1;//自動解決了類型匹配的問題触徐,不用擔心自己手抖觸發(fā)類型轉換異常了
  1. 控件的查找賦值,相當于自動幫我們完成了類似如下操作:
  tv1 = findViewById(R.id.tv1) //確保了自己腦子卡狐赡,忘記給聲明的變量賦值撞鹉,引發(fā)空指針
  1. 控制的數(shù)據(jù)填充操作,也就是其本意數(shù)據(jù)綁定,類似自動完成了如下操作:
tv1.setText(user.getName())

讀前須知

  1. 官網連接:數(shù)據(jù)綁定庫
  2. 本文只講使用層面的對應解析鸟雏,不涉及原理流程之類享郊,這點將在下一篇完善
  3. 本文主要基于官網的使用實例,集合kapt生成的相關代碼孝鹊,來吃透用法背后的真實面紗(源碼)
  4. 本文不涉及配置炊琉,基礎引用等,需要有一定的DataBinding使用經驗惶室,但是只用但是不知道為啥這么用的大佬

按照官網的順序一點一點來

最常見的TexView的text填充
< android:text="@{viewModel.name}" />

對應的賦值模板代碼如下:

//聲明數(shù)據(jù)對應數(shù)據(jù)變量
java.lang.String viewModelName = null;
//數(shù)據(jù)變量賦值
viewModelName = viewModel.getName();
//數(shù)據(jù)綁定View
androidx.databinding.adapters.TextViewBindingAdapter.setText(this.tv1, viewModelName);
//TextViewBindingAdapter是DataBinding庫給我們提供的一個數(shù)據(jù)綁定適配器
//這個方法翻譯過來就是接管了android:text的屬性的賦值邏輯温自,也就是當遇到上面寫法時,會通過下面的靜態(tài)方法進行賦值
//官方提供的了很多皇钞,可以參考著進行更多屬性賦值功能擴展悼泌,這絕對是最好的copy對象
   @BindingAdapter("android:text")
    public static void setText(TextView view, CharSequence text) {
        //下面實現(xiàn)很貼心,對新老內容進行了比較夹界,防止了重復調用view.setText(text);引起的過渡繪制馆里,很值得我們學習哦
        final CharSequence oldText = view.getText();
        if (text == oldText || (text == null && oldText.length() == 0)) {
            return;
        }
        if (text instanceof Spanned) {
            if (text.equals(oldText)) {
                return; // No change in the spans, so don't set anything.
            }
        } else if (!haveContentsChanged(text, oldText)) {
            return; // No content changes, so don't set anything.
        }
        view.setText(text);
    }
帶表達式的
< android:visibility="@{viewModel.age > 10 ? View.VISIBLE : View.GONE}" />

對應的賦值代碼塊如下(上面只是一個簡單的表達式,其實還有很多可柿,但是官方并不太建議在布局寫太復雜的表達式鸠踪,這樣會搞的布局文件很亂,按照Jetpack的整體思路复斥,數(shù)據(jù)的邏輯處理营密,應該的ViewModel中處理,布局里最好是取最終值就好目锭,這里吐槽一點评汰,有些說法是Databind會搞的布局文件很亂,其實是用復雜了而已痢虹,人家官方本意其實指向讓你進行數(shù)據(jù)綁定被去,并不想讓你在布局里做太復雜的數(shù)據(jù)邏輯)

//聲明變量,這個名字很長
int viewModelAgeInt10ViewVISIBLEViewGONE = 0;
//變量賦值
viewModelAgeInt10ViewVISIBLEViewGONE = ((viewModelAgeInt10) ? (android.view.View.VISIBLE) : (android.view.View.GONE));
//數(shù)據(jù)綁定
// ?咦奖唯,這個咋沒適配器呢惨缆。因為Databind,針對屬性有對應setXXX方法會默認調用其setXXX方法就好丰捷,無需提供Adapter
//那android:text坯墨,也有setText()呀,為啥上面有呢病往,因為官方覺得那個方法太簡單了畅蹂,所以給提供了更優(yōu)化的方法,以達到優(yōu)化目的
//也就是說默認的會調用屬性對應的setXXX方法荣恐,如果有適配器定制的話就調用定制的
this.tv3.setVisibility(viewModelAgeInt10ViewVISIBLEViewGONE);
Null合并運算符
< android:text="@{viewModel.name??viewModel.lastName}" />

對應的賦值代碼塊

//聲明變量
java.lang.String viewModelNameJavaLangObjectNullViewModelLastNameViewModelName = null;
//給變量賦值液斜,本質還是用了我們三元運算符累贤,也就是這個就是個語法糖
viewModelNameJavaLangObjectNullViewModelLastNameViewModelName = ((viewModelNameJavaLangObjectNull) ? (viewModelLastName) : (viewModelName));
//給View填充數(shù)據(jù),講過了不啰嗦
androidx.databinding.adapters.TextViewBindingAdapter.setText(this.tv2, viewModelNameJavaLangObjectNullViewModelLastNameViewModelName);
視圖引用
< android:text="@{tv3.text}" />

適用兩個組件取值一致的場景

androidx.databinding.adapters.TextViewBindingAdapter.setText(this.tv3, stringValueOfViewModelAge);
androidx.databinding.adapters.TextViewBindingAdapter.setText(this.tv4, stringValueOfViewModelAge);

其實本質是兩個組件使用了統(tǒng)一個數(shù)據(jù)變量

集合
<!-- 要手動導入,主語xml里不支持‘<’符號少漆,要用&lt代替 -->
<import type="java.util.List"/>
<variable
           name="listdata"
           type="List&lt;String>" />
<!-- 使用 -->
<TextView
android:text="@{viewModel.list[1]}"/>

對應代碼生成的代碼

import java.util.List;
java.util.List<java.lang.String> viewModelList = null;
java.lang.String viewModelList1 = null;
viewModelList = viewModel.getList();
if (viewModelList != null) {
                        // read viewModel.list[1]
                        viewModelList1 = getFromList(viewModelList, 1);
                    }
androidx.databinding.adapters.TextViewBindingAdapter.setText(this.mboundView14, viewModelList1);
//這個方法是ViewDatabinding基類提供的方法臼膏,與之對應還有其它集合類方法,用于獲取集合中某個索引值用
protected static <T> T getFromList(List<T> list, int index) {
        if (list == null || index < 0 || index >= list.size()) {
            return null;
        }
        return list.get(index);
    }
字符串字面量

這個就簡單的說下使用示损,場景上就是咱們的值是在雙引號內的渗磅,里面如果需要字面常量時不能再用雙引號,要用單引號检访;當然如果外層用單引號內層就可以用雙引號了始鱼,總之就是不能同時出現(xiàn)兩個雙引號

<!-- 外單內雙 -->
< android:text='@{"寫死的值"}' />
<!-- 外雙內單 -->
< android:text="@{map[`firstName`]}" />
//到了編譯后就是用的死值,不會為其生成變量
androidx.databinding.adapters.TextViewBindingAdapter.setText(this.tv5, "寫死的值");
資源

主要是資源文件的動態(tài)話

<string name="content">I am %s , age is %d</string>
< android:text='@{@string/content(viewModel.name,viewModel.age)}' />
java.lang.String tv6AndroidStringContentViewModelNameViewModelAge = null;
//可以看到本質上還是調用了tv6.getResources().getString()的方法
tv6AndroidStringContentViewModelNameViewModelAge = tv6.getResources().getString(R.string.content, viewModelName, viewModelAge);
androidx.databinding.adapters.TextViewBindingAdapter.setText(this.tv6, tv6AndroidStringContentViewModelNameViewModelAge);
方法引用
事件處理的一種方式脆贵,官方的解釋是:
  • 在表達式中医清,您可以引用符合監(jiān)聽器方法簽名的方法。當表達式求值結果為方法引用時卖氨,數(shù)據(jù)綁定會將方法引用和所有者對象封裝到監(jiān)聽器中会烙,并在目標視圖上設置該監(jiān)聽器。如果表達式的求值結果為 null筒捺,則數(shù)據(jù)綁定不會創(chuàng)建監(jiān)聽器柏腻,而是設置 null 監(jiān)聽器。
  • 事件可以直接綁定到處理腳本方法系吭,類似于為 Activity 中的方法指定 android:onClick 的方式五嫂。與 ViewonClick` 特性相比,一個主要優(yōu)點是表達式在編譯時進行處理肯尺,因此贫导,如果該方法不存在或其簽名不正確,則會收到編譯時錯誤蟆盹。
  • 方法引用和監(jiān)聽器綁定之間的主要區(qū)別在于實際監(jiān)聽器實現(xiàn)是在綁定數(shù)據(jù)時創(chuàng)建的,而不是在事件觸發(fā)時創(chuàng)建的闺金。如果您希望在事件發(fā)生時對表達式求值逾滥,則應使用監(jiān)聽器綁定

好難懂是吧败匹,那我們接下來就根據(jù)栗子和源碼去理解吧

首先定義一個方法引用寨昙,如下
class ListenerHandler {
    fun tvOnClick(view: View){
        Toast.makeText(view.context,"aaaa",Toast.LENGTH_LONG).show()
    }
}

這個啥特點呢就是方法的參數(shù)與返回值必須與對應事件的參數(shù)類型一致,方法名隨意掀亩,對應到官方的一句話就是”引用符合監(jiān)聽器方法簽名的方法“

<variable
            name="clickHandler"
            type="org.geekbang.databindingtest.ListenerHandler" />

來個錯誤的示范
fun tvOnClick(view: View) --> fun tvOnClick(context: Context);也就是方法簽名搞錯了舔哪,會咋樣呢



會直接有個紅線,提示錯了槽棍,也就是不和規(guī)范在編譯器就不行了
修正過來的寫法

android:onClick="@{clickHandler::tvOnClick}"

那么最終編譯出來的相關代碼是啥呢

//老樣子捉蚤,根據(jù)文件里的東東生成一個變量
android.view.View.OnClickListener clickHandlerTvOnClickAndroidViewViewOnClickListener = null;
private OnClickListenerImpl mClickHandlerTvOnClickAndroidViewViewOnClickListener;
if (clickHandler != null) {
  clickHandlerTvOnClickAndroidViewViewOnClickListener = (((mClickHandlerTvOnClickAndroidViewViewOnClickListener == null) 
       ? (mClickHandlerTvOnClickAndroidViewViewOnClickListener = new OnClickListenerImpl()) 
       : mClickHandlerTvOnClickAndroidViewViewOnClickListener).setValue(clickHandler));
}

翻譯下就是抬驴,如果mXXX==null,則new OnClickListenerImpl()缆巧,否則mXXX.setValue(clickHandler)更新下值
先看否則 clickHandler布持,很明顯就是我們在布局文件中的<variable name="clickHandler">
核心還是那個OnClickListenerImpl,看下源碼

public static class OnClickListenerImpl implements android.view.View.OnClickListener{
        private org.geekbang.databindingtest.ListenerHandler value;
        public OnClickListenerImpl setValue(org.geekbang.databindingtest.ListenerHandler value) {
            this.value = value;
            return value == null ? null : this;
        }
        @Override
        public void onClick(android.view.View arg0) {
            this.value.tvOnClick(arg0); 
        }
    }

這個類能解釋好多官方解釋

  1. 這個類和實例是編譯時就創(chuàng)建陕悬,對應官方的話:方法引用和監(jiān)聽器綁定之間的主要區(qū)別在于實際監(jiān)聽器實現(xiàn)是在綁定數(shù)據(jù)時創(chuàng)建的
  2. 這個類里持有一個變量org.geekbang.databindingtest.ListenerHandler value题暖,這個變量的類型是我們的自定義的實現(xiàn)的類型,值也很明顯就是我們聲明的那個clickHandler捉超;這里對應官方的話:數(shù)據(jù)綁定會將方法引用和所有者對象封裝到監(jiān)聽器中
  3. 接口的實現(xiàn)最終調用的是value對應的方法胧卤;這也就能解釋通為啥定義的方法一定要符合監(jiān)聽器的方法簽名了,也就是參數(shù)上要對應好拼岳,從這里我們可以發(fā)現(xiàn)枝誊,其實不一定參數(shù)類型完全一致,只要是事件方法參數(shù)的子類類型就可以了裂问,不過一般設置接口時就會根據(jù)依賴倒置規(guī)則確定了類型上不能再具體了侧啼。

最后肯定是設置值了,這一些列操作編譯時相當于都把代碼給我們寫好了堪簿,至此所謂的方法引用方式綁定事件處理就通了

this.tv1.setOnClickListener(clickHandlerTvOnClickAndroidViewViewOnClickListener);
監(jiān)聽器綁定
也是事件處理的一種方式痊乾,官方的解釋來一波:
  • 這些是在事件發(fā)生時進行求值的 lambda 表達式。數(shù)據(jù)綁定始終會創(chuàng)建一個要在視圖上設置的監(jiān)聽器椭更。事件被分派后哪审,監(jiān)聽器會對 lambda 表達式進行求值。
  • 監(jiān)聽器綁定是在事件發(fā)生時運行的綁定表達式虑瀑。它們類似于方法引用湿滓,但允許您運行任意數(shù)據(jù)綁定表達式。
  • 在方法引用中舌狗,方法的參數(shù)必須與事件監(jiān)聽器的參數(shù)匹配叽奥。在監(jiān)聽器綁定中,只有您的返回值必須與監(jiān)聽器的預期返回值相匹配(預期返回值無效除外)

定義痛侍,聲明朝氓,使用

class ListenerHandler {
   fun onClickByInfo(view:View,text:CharSequence){
        Toast.makeText(view.context,text,Toast.LENGTH_LONG).show()
    }
}
<variable
           name="clickHandler"
           type="org.geekbang.databindingtest.ListenerHandler" />
< android:onClick="@{(view)->clickHandler.onClickByInfo(view,viewModel.name)}" />

理一下生成的相關代碼,我們倒著看比較好主届,這里倒著看下

//給tv設置監(jiān)聽,這里的callBack肯定是一個OnClickListener
this.tv2.setOnClickListener(mCallback1);
// 果不其然赵哲,直接就是
@Nullable
 private final android.view.View.OnClickListener mCallback1;
// 那他賦值是誰呢,看下面,這個有兩個參數(shù)君丁,傳了this->ActivityMainBinding枫夺,還有一個1?,這個1是干啥的。绘闷∠鹋樱〗咸常現(xiàn)在不清楚
mCallback1 = new org.geekbang.databindingtest.generated.callback.OnClickListener(this, 1);
//看看這個類的實現(xiàn)
package org.geekbang.databindingtest.generated.callback;
public final class OnClickListener implements android.view.View.OnClickListener {
    final Listener mListener;
    final int mSourceId;
    public OnClickListener(Listener listener, int sourceId) {
        mListener = listener;
        mSourceId = sourceId;
    }
    @Override
    public void onClick(android.view.View callbackArg_0) {
        //我們點擊按鈕時會調這里,這個的具體實現(xiàn)交給了內部接口實例mListener的_internalCallbackOnClick方法去實現(xiàn)了
        mListener._internalCallbackOnClick(mSourceId , callbackArg_0);
    }
    public interface Listener {
        void _internalCallbackOnClick(int sourceId , android.view.View callbackArg_0);
    }
}
接下來就看那個接口的實現(xiàn)在哪里毙死,通過開始的賦值也能才到燎潮,實現(xiàn)在ActivityMainBinding,那么就看具體實現(xiàn)
public final void _internalCallbackOnClick(int sourceId , android.view.View callbackArg_0) {
        boolean clickHandlerJavaLangObjectNull = false;
        java.lang.String viewModelName = null;
        org.geekbang.databindingtest.ListenerHandler clickHandler = mClickHandler;
        org.geekbang.databindingtest.MainViewModel viewModel = mViewModel;
        boolean viewModelJavaLangObjectNull = false;
        clickHandlerJavaLangObjectNull = (clickHandler) != (null);
        if (clickHandlerJavaLangObjectNull) {
            viewModelJavaLangObjectNull = (viewModel) != (null);
            if (viewModelJavaLangObjectNull) {
                viewModelName = viewModel.getName();
                //上面都是變量聲明和檢測扼倘,其實可以看出來就是各種非空邏輯的判斷确封,要確保不出現(xiàn)空指針
               //這里最終調用了我們定義的方法
                clickHandler.onClickByInfo(callbackArg_0, viewModelName);
            }
        }
    }

從上面源碼看,相比方法引用其實就是換了下寫法再菊,同時支持非簽名參數(shù)了而已爪喘,因為這些代碼也都是編譯時都設置好了。
那么這兩種看都是將原來的onClick的具體實現(xiàn)最終轉給了我們自己寫的業(yè)務塊纠拔,只是方法參數(shù)上監(jiān)聽器比方法引用更加靈活秉剑,這里可以推斷出場景選擇,點擊事件不依賴于數(shù)據(jù)邏輯時用方法引用就好稠诲,如果依賴于數(shù)據(jù)侦鹏,比如我們的Rv的Item里的點擊需要把Item的data帶出去,就可以用監(jiān)聽器引用了臀叙。

可觀察數(shù)據(jù)對象

這個其實在實際中都以LiveData代替了略水,這最終是如何運行的,且看下回分解劝萤。我們就通過一個簡單的LiveData實例看看有啥相關代碼渊涝。

val descriptionInfo = MutableLiveData("簡介")
< android:text="@={viewModel.descriptionInfo}" />

倒著看看相關代碼

//賦值
androidx.databinding.adapters.TextViewBindingAdapter.setText(this.tvDes, viewModelDescriptionInfoGetValue);
//相關變量聲明,能看到有兩個變量床嫌,一個是值跨释,一個是LiveData
androidx.lifecycle.MutableLiveData<java.lang.String> viewModelDescriptionInfo = null;
java.lang.String viewModelDescriptionInfoGetValue = null;
//值肯定通過LiveData獲取的
if (viewModelDescriptionInfo != null) {
    viewModelDescriptionInfoGetValue = viewModelDescriptionInfo.getValue();
}
// LiveData通過變量賦值
if (viewModel != null) {
   // read viewModel.descriptionInfo
   viewModelDescriptionInfo = viewModel.getDescriptionInfo();
 }
//賦值后還有個下面的方法,從這里順下去應該能找出是如何響應LiveData變化的
 updateLiveDataRegistration(1, viewModelDescriptionInfo);
 /**
  * 更新liveData的的注冊器
  * 本地字段id
  * LiveData自己厌处,算是一個observable
  */
protected boolean updateLiveDataRegistration(int localFieldId, LiveData<?> observable) {
        mInLiveDataRegisterObserver = true;
        try {
            //最終給了updateRegistration鳖谈,參數(shù)CREATE_LIVE_DATA_LISTENER,這個方法最其實就是經過關聯(lián)判斷阔涉,合理的去給LiveData去更新下觀察者缆娃,就不展開了
            return updateRegistration(localFieldId, observable, CREATE_LIVE_DATA_LISTENER);
        } finally {
            mInLiveDataRegisterObserver = false;
        }
    }
  //CREATE_LIVE_DATA_LISTENER是啥?可以看到其本質是LiveDataListener洒敏,是ViewDataBinding的靜態(tài)常量。那就瞅一眼疙驾,有點多凶伙,我們只關注下核心的
//implements Observer是一個觀察者
private static class LiveDataListener implements Observer,
            ObservableReference<LiveData<?>> {
        //一個監(jiān)聽相關的數(shù)據(jù)包裝類,將各個參數(shù)存到這里面了
        final WeakListener<LiveData<?>> mListener;
            //略...
            mListener = new WeakListener(binder, localFieldId, this, referenceQueue);
           //略...
           //會給LiveData設置監(jiān)聽
           liveData.observe(newOwner, this);
           //略...
        //響應監(jiān)聽變化
        public void onChanged(@Nullable Object o) {
            ViewDataBinding binder = mListener.getBinder();
            if (binder != null) {
                binder.handleFieldChange(mListener.mLocalFieldId, mListener.getTarget(), 0);
            }
        }
    }

從上線我們能看到當生性周期狀態(tài)變化后它碎,會交由ViewDataBinding的handleFieldChange去響應變化函荣,接下來我們跟一下這條線的主要代碼

 //如果字段變化后會走requestRebind
boolean result = onFieldChange(mLocalFieldId, object, fieldId);
        if (result) {
            requestRebind();
        }
 //requestRebind是請求重新綁定的意思显押,最終繞來繞去會走到executeBindings();而executeBindings是執(zhí)行綁定的意思,最終會回到我們開始的賦值階段

從上面看傻挂,我們的LiveData數(shù)據(jù)的管理還是有點復雜的乘碑,主要是很多預制的東西,本質上還是注冊觀察者和響應觀察者而已金拒,只是將這一套流程模板化了而已

綁定適配器
自己的理解
  • 這個官網講述的都已經很詳細了兽肤,這里主要是做做總結,加深下理解绪抛,沒興趣的可以直接看官網资铡。
  • 綁定的實質是設置控件的某個屬性,如setText是改變文字幢码,setAlpha是改變透明度笤休,那么要改變這個屬性可能需要一些邏輯去定制,比如setText症副,如果新舊值沒有變化就沒必要設置了店雅,多刷新一次而已,那么適配器的本質作用就是為設置屬性提供自定義實現(xiàn)方式贞铣,類似于RecycleView中我們將布局填充交給Adapter一樣闹啦,這里是我們將某個屬性的修改交給了一個Adapter而已。
適配器的定制原則
  1. 理論上任何屬性都可以定制
  2. 自動選擇:有setter方法的都可以直接搞
    • 有屬性有對應的setter方法咕娄,可以直接用亥揖;例如android:gravity="@{vm.gravity}"
    • 沒有屬性,但是有setter方法圣勒,可以通過app:xxx="xxx"方式使用费变;例如app:scrimColor="@{@color/scrim}"
  3. 指定自定義方法名稱:有屬性,但是沒有對應的setter圣贸,但是呢有其它名稱的方法可以單獨修改這個屬性挚歧,可以將屬性及方法建立關聯(lián)即可。例如android:tint這個屬性吁峻,木有setTint方法滑负,但是有setImageTintList方法是用來設置各個屬性的,我們通過一下方法進行關鍵即可用含。示例:
    @BindingMethods(value = [
            BindingMethod(
                type = android.widget.ImageView::class,
                attribute = "android:tint",
                method = "setImageTintList")])
    
    其實這個有矮慕,但是很少,首先一般寫法都是用對應setter方法啄骇,及時需要關聯(lián)的痴鳄,大多數(shù)DataBinding框架已經幫我們建立關聯(lián)了,發(fā)現(xiàn)木有時到androidx.databinding.adapters下找找看缸夹。
  4. 完全自定義:這個就是既沒有默認痪寻,也無法1v1關聯(lián)的場景了螺句;例如我們有android:paddingLeft屬性,但沒有該屬性的sePaddingLeft,有改變的方法setPadding但這個哥們是四個參數(shù)是改四個padding值用的橡类,也就是完全驢唇對不上馬嘴蛇尚,就只能自定義了,這也是我們大多數(shù)場景了顾画。
    • 這個主要是單參數(shù)取劫,組合參數(shù)的情況,官網給了明確的示例亲雪,并且官方庫也提供了很多封裝勇凭,比著葫蘆畫瓢就好。注意在Kotlin中比官方更簡單點义辕,因為Kotlin可以用擴展函數(shù)實現(xiàn)虾标,省了一個參數(shù)的聲明
    • @BindingAdapter 其實讀一下這個注解的源碼及注釋就一通百通了
對象轉換
  • 我們目標上在綁定數(shù)據(jù)時需要確保與屬性的值類型一致,如我們gravity屬性需要一個int灌砖,我們給一個字符串類型的肯定不合適璧函。但是某些邏輯下我們得到的可能并不是int類型,這就需要轉換了基显。轉換的目的是讓值能符合屬性設置的類型要求蘸吓。
  • 自動轉換:有些屬性可以支持多種類型,比如setText撩幽,可以是int的resId库继,可以是String類型,自動轉換的理解就是可以根據(jù)給定的值類型自動選擇調用哪個方法來設置屬性窜醉。
  • 自定義轉換:就是原始值不滿足屬性值的類型要求宪萄;舉兩個例子,backGround屬性需要Drawable榨惰,我們給@color/xxx肯性不行拜英,還有一個較為常見的場景,我們一般拿到的時間戳琅催,但是需要顯示的是xxxx年xx月xx日的格式居凶。定義方法比較簡單,就是在方法上加個@BindingConversion就可以了藤抡。咱們用個例子看下
    // 我們有一個user對象
    val user = User("二胖胖",18)
    
    <!-- 給text直接指定了對象了,理論上我們木有setText(user:User)類型的方法的 -->
    < android:text="@{viewModel.user}" />
    
    我們定義個轉義器
    @BindingConversion
    fun convertUserToString(user: User): String? {
        return user.toString()
    }
    
    看下最終表現(xiàn)
    androidx.databinding.adapters.TextViewBindingAdapter.setText(this.tv9, org.geekbang.databindingtest.ViewExBindingAdaptersKt.convertUserToString(viewModelUser));
    
    也就是編譯器會發(fā)現(xiàn)類型不匹配會找對應的covert方法來用
雙向綁定
  • 首先這個東西看官網得看幾遍缠黍,個人覺得不是很好理解
  • 其實掌握以下就可以了
    1. 這個的應用場景就是弄兜,某個UI依賴一個數(shù)據(jù)展示,這個UI的內容變化后會改變這個數(shù)值;例如EditText挨队,我們初始值依賴一個變量value,隨著輸入的變化輸入框的值會實時改變value的值蒿往,翻譯過來就是通過簡單的寫法可以實現(xiàn)如下兩個操作:
       editText.text = value
       editText.addTextChangedListener(object : TextWatcher(){
            override fun afterTextChanged(s: Editable?) {
                value = s.toString()
            }
        })
      
    2. 寫法的話就是語法糖@=
      < android:text="@={value}" />
      
    3. 系統(tǒng)提供了大多數(shù)使用場景雙向特性
    4. 想自定義的話盛垦,需要掌握幾個注解用法 @BindingAdapter @InverseBindingAdapter @InverseBindingMethods
ViewStub
  • 額...沒咋用過...也就沒深入研究了,但是這個是布局優(yōu)化的一個點瓤漏,有興趣深究下就好
include
  • 本質只是一個DataBinding的包裹腾夯,掌握傳值就好了,不過這里寫演示實例時遇到個坑蔬充,就是在約束布局里的寬高用wrapper不行蝶俱,了解下就好了。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末饥漫,一起剝皮案震驚了整個濱河市榨呆,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌庸队,老刑警劉巖积蜻,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異彻消,居然都是意外死亡竿拆,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進店門宾尚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來丙笋,“玉大人,你說我怎么就攤上這事煌贴∮澹” “怎么了?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵崔步,是天一觀的道長稳吮。 經常有香客問我,道長井濒,這世上最難降的妖魔是什么灶似? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮瑞你,結果婚禮上酪惭,老公的妹妹穿的比我還像新娘。我一直安慰自己者甲,他們只是感情好春感,可當我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般鲫懒。 火紅的嫁衣襯著肌膚如雪嫩实。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天窥岩,我揣著相機與錄音甲献,去河邊找鬼。 笑死颂翼,一個胖子當著我的面吹牛晃洒,可吹牛的內容都是我干的。 我是一名探鬼主播朦乏,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼球及,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了呻疹?” 一聲冷哼從身側響起吃引,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎刽锤,沒想到半個月后际歼,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡姑蓝,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年鹅心,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纺荧。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡旭愧,死狀恐怖,靈堂內的尸體忽然破棺而出宙暇,到底是詐尸還是另有隱情输枯,我是刑警寧澤,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布占贫,位于F島的核電站桃熄,受9級特大地震影響,放射性物質發(fā)生泄漏型奥。R本人自食惡果不足惜瞳收,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望厢汹。 院中可真熱鬧螟深,春花似錦、人聲如沸烫葬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至垢箕,卻和暖如春划栓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背条获。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工茅姜, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人月匣。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像奋姿,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內容