DataBinding·常用注解說明

android.databinding

@Bindable

Observable接口提供給開發(fā)者添加/移除監(jiān)聽者的機(jī)制。為了使開發(fā)更便捷,我們創(chuàng)建了BaseObservable類,它已經(jīng)實(shí)現(xiàn)了Observable接口中的注冊監(jiān)聽者的機(jī)制。

繼承自BaseObservable的數(shù)據(jù)類,仍需手動(dòng)的通知監(jiān)聽者們數(shù)據(jù)已發(fā)生變更。你可以在setter方法中發(fā)出變更消息,記住同時(shí)在getter方法上標(biāo)記注解@Bindable。

@Bindable 注解的推薦用法 是修飾繼承自Observable類中的getter accessor方法,但其實(shí)getter accessor的屬性也是可以應(yīng)用該注解的。

注解@Bindable在編譯期間生成一個(gè)BR類,以此持有對應(yīng)的實(shí)例,作用同R類。

private static class User extends BaseObservable {
   private String firstName;
   @Bindable
   public String getFirstName() {
       return this.firstName;
   }
   public void setFirstName(String firstName) {
       this.firstName = firstName;
       notifyPropertyChanged(BR.firstName);
   }
}

@BindingAdapter

應(yīng)用于用于操作表達(dá)式的值如何設(shè)置為視圖的方法。

@BindingAdapter用于修飾方法。

一些屬性需要定制綁定邏輯,一個(gè)用@BindingAdapter修飾的靜態(tài)方法可以自定義屬性的setter操作。

android自身實(shí)現(xiàn)了大量的Adapter,你可以在項(xiàng)目moduleandroid.databinding.adapters包下找到這些代碼。

public class CardViewBindingAdapter {
    @BindingAdapter("contentPadding")
    public static void setContentPadding(CardView view, int padding) {
        view.setContentPadding(padding, padding, padding, padding);
    }
}

1、默認(rèn)的你的自定義的命名空間,在匹配時(shí)會被忽略。

@BindingAdapter("contentPadding")

2、允許重寫android的命名空間。

@BindingAdapter("android:contentPadding")

app:contentPaddingandroid:contentPadding處理行為可以不一樣。
app:contentPaddingcustom:contentPadding處理行為是一致的。(僅android是特殊的命名空間)。

需要注意,當(dāng)你創(chuàng)建的適配器屬性與系統(tǒng)默認(rèn)的產(chǎn)生沖突時(shí),你的自定義適配器將會覆蓋掉系統(tǒng)原先定義的注解,這將會產(chǎn)生一些意外的問題。

假設(shè)需要對下面接口,做適配。

public interface ILogAction{
      void login();
      void logout();
}

則需要一個(gè)方法一個(gè)接口,這么做的原因是避免login()的修改影響到logout()。所以根據(jù)業(yè)務(wù)需要,可能需要排列組合適配這兩個(gè)接口。

1、適配 login
2、適配 logout
3、適配 login + logout

@BindingBuildInfo

@BindingBuildInfo(
buildId="3fefc6ba-1e95-4dcf-8ffa-278fe0f449bd",
modulePackage="com.ipudong.library",
sdkRoot="/Users/robert/Library/Android/sdk",
layoutInfoDir="/Users/robert/android/develops/pudong-d-android/lib_basic/build/intermediates/data-binding-info/debug",
exportClassListTo="/Users/robert/android/develops/pudong-d-android/lib_basic/build/intermediates/data-binding-info/debug/_generated.txt",
isLibrary=true,
minSdk=14,
enableDebugLogs=false,
printEncodedError=true
)
public class DataBindingInfo {}

SOURCE階段會自動(dòng)生成DataBindingInfo.class,并標(biāo)記注解如上。

@BindingConversion

Annotate methods that are used to automatically convert from the expression type to the value used in the setter.

有時(shí)候會遇到類型不匹配的問題,比如R.color.whiteint,但是通過Data Binding賦值給android:background屬性后,需要把int轉(zhuǎn)換為ColorDrawable

@BindingConversion
public static Drawable convertColorToDrawable(int drawable) {
  return new ColorDrawable(drawable);
}

@BindingMethod && @BindingMethods

Used within an BindingMethods annotation to describe a renaming of an attribute to the setter used to set that attribute.
Used to enumerate attribute-to-setter renaming.

@BindingMethods用于修飾類。

一些屬性雖然擁有setters但是并不與名字相匹配,這些方法的屬性可以通過 @BindingMethod && @BindingMethods 注釋 setters

@BindingMethods({
       @BindingMethod(type = "android.widget.ImageView",
                      attribute = "android:tint",
                      method = "setImageTintList"),
})

開發(fā)人員不太可能需要重命名 setters ,因?yàn)閍ndroid框架屬性已經(jīng)實(shí)現(xiàn)了這一部分。

@InverseBindingAdapter

InverseBindingAdapter用于關(guān)聯(lián)某個(gè)用于接收View變更的方法,典型的例子EditText.TextWatcher接收輸入字符的變更。這與BindingAdapters有一定的相似性:

 @InverseBindingAdapter(attribute = "android:text", event = "android:textAttrChanged")
 public static String captureTextValue(TextView view, CharSequence originalValue) {
     CharSequence newValue = view.getText();
     CharSequence oldValue = value.get();
     if (oldValue == null) {
         value.set(newValue);
     } else if (!contentEquals(newValue, oldValue)) {
         value.set(newValue);
     }
 }

事件的默認(rèn)值是帶有AttrChanged的屬性名稱。在上面的例子中,默認(rèn)值是android:textAttrChanged,即使它沒有提供。

事件屬性用于通知數(shù)據(jù)綁定系統(tǒng)值已更改。開發(fā)人員通常會創(chuàng)建一個(gè)BindingAdapter來分配事件。比如:

@BindingAdapter(value = {"android:beforeTextChanged", "android:onTextChanged",
                          "android:afterTextChanged", "android:textAttrChanged"},
                          requireAll = false)
 public static void setTextWatcher(TextView view, final BeforeTextChanged before,
                                   final OnTextChanged on, final AfterTextChanged after,
                                   final InverseBindingListener textAttrChanged) {
     TextWatcher newValue = new TextWatcher() {
         ...
         @Override
         public void onTextChanged(CharSequence s, int start, int before, int count) {
             if (on != null) {
                 on.onTextChanged(s, start, before, count);
             }
             if (textAttrChanged != null) {
                 textAttrChanged.onChange();
             }
         }
     }
     TextWatcher oldValue = ListenerUtil.trackListener(view, newValue, R.id.textWatcher);
     if (oldValue != null) {
         view.removeTextChangedListener(oldValue);
     }
     view.addTextChangedListener(newValue);
 }
 

如同BindingAdapters一樣, InverseBindingAdapter方法 也可以將 DataBindingComponent作為第一個(gè)參數(shù),可以是具有從DataBindingComponent檢索的實(shí)例的實(shí)例方法。

InverseBindingListener 非常有用。 參考 InverseBindingListener

@InverseBindingMethod

InverseBindingMethod用于標(biāo)識如何監(jiān)聽對View屬性的更改以及要調(diào)用的getter方法。 InverseBindingMethod 應(yīng)該與InverseBindingMethods的部分方法相關(guān)聯(lián)。

@InverseBindingMethods({@InverseBindingMethod(
     type = android.widget.TextView.class,
     attribute = "android:text",
     event = "android:textAttrChanged",
     method = "getText")})
 public class MyTextViewBindingAdapters { ... }

@InverseBindingMethods中的屬性method 是可選的。

如果其沒有提供, 屬性名稱會查找如下幾種可能性:方法名稱,前綴為is或者get的方法名稱。 如屬性android:text, 數(shù)據(jù)綁定框架會在TextView中搜索public CharSequence getText() 方法。

@InverseBindingMethods中的屬性event是可選的。

如果其沒有提供,默認(rèn)會使用屬性名+AttrChanged后綴。如屬性android:text, 默認(rèn)的事件名稱android:textAttrChanged。

這個(gè)事件也需要配置相關(guān)的@BindingAdapter,如下:

 @BindingAdapter(value = {"android:beforeTextChanged", "android:onTextChanged",
                          "android:afterTextChanged", "android:textAttrChanged"},
                          requireAll = false)
 public static void setTextWatcher(TextView view, final BeforeTextChanged before,
                                   final OnTextChanged on, final AfterTextChanged after,
                                   final InverseBindingListener textAttrChanged) {
     TextWatcher newValue = new TextWatcher() {
         ...
         @Override
         public void onTextChanged(CharSequence s, int start, int before, int count) {
             if (on != null) {
                 on.onTextChanged(s, start, before, count);
             }
             if (textAttrChanged != null) {
                 textAttrChanged.onChange();
             }
         }
     }
     TextWatcher oldValue = ListenerUtil.trackListener(view, newValue, R.id.textWatcher);
     if (oldValue != null) {
         view.removeTextChangedListener(oldValue);
     }
     view.addTextChangedListener(newValue);
 }
 

@InverseBindingMethods

用于枚舉屬性,getter和事件關(guān)聯(lián)。

@Untaggable

Data Binding相關(guān)的jar包由四部分組成,

  1. baseLibrary-2.1.0-rc1.jar
    作為運(yùn)行時(shí)類庫被打進(jìn)APK中;

  2. DataBinderPlugin(gradle plugin)
    在編譯期使用,利用gradle-api(之前叫transform-api,1.5生,2.0改名)處理xml文件,生成DataBindingInfo.java;

  3. compiler-2.1.0-rc1.jar
    在編譯器使用,入口類繼承自AbstractProcessor,用于處理注解,并生成Binding類,DataBindingCompoent.java,DataBinderMapper.java類;

  4. compilerCommon-2.1.0-rc1.jar
    被DataBinderPlugin和compiler-2.1.0-rc1.jar所依賴

相關(guān)編譯流程

STEP1 資源處理

aapt或者gradle執(zhí)行時(shí),都會觸發(fā)資源處理。
在資源處理過程中,DataBinding都會掃描一遍現(xiàn)有的資源,生成不包含<layout>的data-binding-layout-out以及DataBinding所需要的data-binding-info;

STEP2 DataBindingInfo.class生成

在完成資源處理后,aapt或者gradle-api都會去執(zhí)行DataBindingInfo.class生成操作,把相關(guān)的信息寫入DataBindingInfo.class的@BindingBuildInfo注解中;

STEP3 監(jiān)聽到注解變化

生成@BindingBuildInfo注解,或者code中發(fā)現(xiàn)有新的注解寫入,AbstractProcessor注解處理器就開始執(zhí)行注解處理。
DataBinding中有一個(gè)ProcessDataBinding.java類專門來處理DataBinding相關(guān)的注解;

STEP4 ProcessDataBinding處理注解,生成bin

ProcessDataBinding中處理注解永遠(yuǎn)會按順執(zhí)行3步,ProcessMethodAdapter,ProcessExpressions,ProcessBindable。
每次執(zhí)行都會從磁盤反序列化對應(yīng)的bin文件,然后往bin中寫入新的,完成后再序列化到磁盤;

STEP5 生成最終產(chǎn)物

執(zhí)行ProcessMethodAdapter生成DataBindingComponents.class;
執(zhí)行ProcessExpressions生成ViewDataBinding.class子類(ActivityDetail2Binding.class),并觸發(fā)DataBindingMapper.class更新;
執(zhí)行ProcessBindable生成BR.class,并觸發(fā)DataBindingMapper.class更新;


參考鏈接:
http://www.itdecent.cn/p/eb29c691d370
https://developer.android.com/topic/libraries/data-binding/index.html
https://developer.android.com/reference/android/databinding/InverseBindingAdapter.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容