精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

【實(shí)戰(zhàn)】Android Data Binding從抵觸到愛不釋手

移動(dòng)開發(fā) Android
目前Android Data Binding在運(yùn)行類庫只有632個(gè)方法數(shù),算上每個(gè)layout.xml自動(dòng)生成的ViewDataBinding子類(demo中每個(gè)類不超過20個(gè)方法數(shù)),方法數(shù)總和也非常有限。

1 引入

如何高效地實(shí)現(xiàn)以下界面?

 

登錄/未登錄

有好幾年findViewById實(shí)戰(zhàn)經(jīng)驗(yàn)的我,感覺并不難啊。一般會(huì)

1.先定義一個(gè)User的Model類,數(shù)據(jù)來自JSON解析;

2.創(chuàng)建一個(gè)xml,隨后在xml中布局完所有View,對頭像、標(biāo)題、積分、登錄按鈕一個(gè)id;

3.在Activity中通過findViewById獲取到頭像ImageView、標(biāo)題TextView、積分TextView、登錄Button,然后給Button設(shè)置監(jiān)聽器,再根據(jù)登陸狀態(tài)展示對應(yīng)數(shù)據(jù);

實(shí)現(xiàn)如下:

  • User.java 

 

  • activity_detail.xml

 

  • DetailActivity

 

2 去掉煩人的findViewById(View注入)

可以看到,在Activity中View的定義、find、判空占據(jù)了大量篇幅,我們需要更優(yōu)雅的實(shí)現(xiàn)。

2.1 ButterKnife

你可能聽說過Jake Wharton的ButterKnife,這個(gè)庫只需要在定義View變量的時(shí)候通過注解傳入對應(yīng)id,隨后在onCreate時(shí)調(diào)用ButterKnife.bind(this)即可完成view的注入,示例如下:

 

2.2 Android Data Binding

如果使用了Android Data Binding,那么View的定義、find、判空這些都不用寫了,如何做呢?

2.2.1 準(zhǔn)備工作

首先,你需要滿足一個(gè)條件:你的Android Plugin for Gradle版本必須等于或高于1.5.0-alpha1版本,這個(gè)版本位于根目錄build.gradle中,示例如下:

  1. buildscript { 
  2.     repositories { 
  3.         jcenter() 
  4.     } 
  5.     dependencies { 
  6.         classpath 'com.android.tools.build:gradle:2.1.0-rc1' 
  7.     } 
  8.  

接著,你必須告訴編譯器開啟Data Binding,一般位于app:build.gradle的android標(biāo)簽中,示例如下:

  1. android { 
  2.     compileSdkVersion 23 
  3.     buildToolsVersion "23.0.2" 
  4.  
  5.     dataBinding { 
  6.         enabled true 
  7.     } 
  8.     ... 
  9.  

2.2.2 修改layout.xml

以activity_detail.xml為例,原來的根節(jié)點(diǎn)為LinearLayout,如下所示:

 

2.2.3 開始享受樂趣吧!

在上述操作完成后,編譯器會(huì)自動(dòng)為我們生成

com.asha.demo.databinding.ActivityDetail2Binding.java類,這個(gè)類的命令方式為:包名 + databinding + activity_detail2駝峰命名方式 + Binding.java。隨后,使用這個(gè)activity_detail2的DetailActivity2.java的代碼可以簡化為:

  1. public class DetailActivity2 extends AppCompatActivity { 
  2.  
  3.     ActivityDetail2Binding binding;    @Override 
  4.     protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState); 
  5.         binding = DataBindingUtil.setContentView(this,R.layout.activity_detail2); 
  6.  
  7.         login(); 
  8.     }    private void login(){ fill(User.newInstance()); }    private void logout(){ fill(null); }    private void fill(final User user){        final int visibility = user != null ? View.VISIBLE : View.GONE;        if (user != null){ 
  9.             binding.detailAvatar.setImageDrawable(ContextCompat.getDrawable(this,user.getAvatar())); 
  10.             binding.detailName.setText(user.getName()); 
  11.             binding.detailDesc.setText(String.format("積分:%d 等級:%d",user.getScore(),user.getLevel())); 
  12.         } 
  13.  
  14.         binding.detailAvatar.setVisibility(visibility); 
  15.         binding.detailName.setVisibility(visibility); 
  16.         binding.detailDesc.setVisibility(visibility); 
  17.         binding.detailActionButton.setOnClickListener(new View.OnClickListener() {                @Override 
  18.                 public void onClick(View v) {                if (user == null) login();                else logout(); 
  19.             } 
  20.         }); 
  21.         binding.detailActionButton.setText(user == null ? "登錄":"退出登錄"); 
  22.     } 

是的,所有View的定義、find、判空都不見了,所有的這些操作都在編譯器為我們生成的ActivityDetail2Binding.java中完成,只需要在onCreate時(shí)調(diào)用如下代碼進(jìn)行setContentView即可實(shí)現(xiàn),

binding = DataBindingUtil.setContentView(this,R.layout.activity_detail2);

我的天哪

2.2.4 ActivityDetail2Binding中注入View相關(guān)的代碼分析

可以在as中方便的查看編譯器自動(dòng)生成的類,這個(gè)類位于/app/build/intermediates/classes/debug/com/asha/demo/databinding/ActivityDetail2Binding.class中,縮減掉Binding邏輯后的代碼為:

 

其中全局靜態(tài)SparseIntArray數(shù)組中存放了4個(gè)數(shù)字,這個(gè)四個(gè)數(shù)字為R.java中生成的對應(yīng)View的id,

  1. public final class R { 
  2.     ...    public static final class id { 
  3.         ...        public static final int detail_action_button = 2131492951;        public static final int detail_avatar = 2131492948;        public static final int detail_desc = 2131492950;        public static final int detail_name = 2131492949; 
  4.         ... 
  5.     } 
  6.     ... 

 在ActvityDetail2Binding實(shí)例構(gòu)造的時(shí)候調(diào)用了mapBindings,一次解決了所有View的查找,mapBindings函數(shù)在ActvityDetail2Binding父類ViewDataBinding中實(shí)現(xiàn)。

3 使用表達(dá)式在layout.xml中填充model數(shù)據(jù)

在ActivityDetail2.java中還存在大量的View控制、數(shù)據(jù)填充代碼,如何把這些代碼在交給layout.xml完成呢?

3.1 ModelAdapter類

第2節(jié)中已經(jīng)定義了User.java類作為Model類,但是我們經(jīng)常會(huì)遇到Model類和真正View展示不一致的情況,本例子中定義一個(gè)來ModelAdapter類來完整Model數(shù)據(jù)到展示數(shù)據(jù)的適配。示例代碼為ActivityDetail3.java的內(nèi)部類,可以調(diào)用ActivityDetail3.java中的函數(shù),代碼定義如下:

 

3.2 activity_detail3.xml中使用model

同樣復(fù)制一份activity_detail2.xml為activity_detail3.xml,在<layout>節(jié)點(diǎn)加入<data>節(jié)點(diǎn),并且在里面定義需要用的model類(比如ModelAdapter adapter),當(dāng)然也可以是基礎(chǔ)類型變量(比如int visibility);

隨后,就可以在下面的view中使用表達(dá)式了,全部布局文件如下:

  1. <?xml version="1.0" encoding="utf-8"?><layout xmlns:android="http://schemas.android.com/apk/res/android"
  2.     <data> 
  3.         <variable name="adapter" type="com.asha.demo.DetailActivity3.ModelAdapter"/> 
  4.         <variable name="visibility" type="int"/> 
  5.     </data> 
  6.     <LinearLayout 
  7.         android:orientation="vertical" android:layout_width="match_parent" 
  8.         android:layout_height="match_parent"
  9.         <View 
  10.             android:background="@color/detail_background" 
  11.             android:layout_width="match_parent" 
  12.             android:layout_height="66dp"
  13.         </View
  14.         <ImageView 
  15.             android:src="@{adapter.avatar}" 
  16.             android:visibility="@{visibility}" 
  17.             android:id="@+id/detail_avatar" 
  18.             android:layout_gravity="center" 
  19.             android:layout_marginTop="-33dp" 
  20.             android:layout_width="66dp" 
  21.             android:layout_height="66dp" /> 
  22.         <TextView 
  23.             android:visibility="@{visibility}" 
  24.             android:text="@{adapter.name}" 
  25.             android:id="@+id/detail_name" 
  26.             android:textSize="17sp" 
  27.             android:textColor="@color/textColorPrimary" 
  28.             android:layout_marginTop="15dp" 
  29.             android:layout_gravity="center" 
  30.             android:layout_width="wrap_content" 
  31.             android:layout_height="wrap_content" /> 
  32.         <TextView 
  33.             android:visibility="@{visibility}" 
  34.             android:text="@{adapter.desc}" 
  35.             android:id="@+id/detail_desc" 
  36.             android:layout_marginTop="15dp" 
  37.             android:textSize="13sp" 
  38.             android:layout_gravity="center" 
  39.             android:layout_width="wrap_content" 
  40.             android:layout_height="wrap_content" /> 
  41.         <Button 
  42.             android:text="@{adapter.actionText}" 
  43.             android:onClick="@{adapter.clickHandler}" 
  44.             android:id="@+id/detail_action_button" 
  45.             android:layout_marginTop="15dp" 
  46.             android:layout_gravity="center" 
  47.             android:textColor="@color/white" 
  48.             android:background="@drawable/selector_g_button" 
  49.             android:layout_width="220dp" 
  50.             android:layout_height="wrap_content" /> 
  51.     </LinearLayout></layout>  

3.3 DetailActivity3.java中調(diào)用填充

如下代碼所示,只需要在登錄狀態(tài)改變的時(shí)候,給viewDataBinding設(shè)置所需要的adatper、visibility值,即可完成數(shù)據(jù)的填充

 

3.4 ActivityDetail3Binding中填充相關(guān)的代碼分析

同樣,ActivityDetail3Binding中,編譯器根據(jù)activity_detail3.xml中的<data>標(biāo)簽,自動(dòng)生成了諸如setAdapter、setVisibility的代碼,setAdapter相關(guān)代碼如下:

 非常簡單,自動(dòng)生成了getter和setter,在完成set操作后,調(diào)用執(zhí)行notifyPropertyChanged和super.requestRebind()

  • notifyPropertyChanged

ViewDataBinding本身就是一個(gè)BaseObservable, 在往ViewDataBinding注冊觀察某個(gè)屬性的變化,如果注冊了mAdapter的變化,對應(yīng)的觀察器就會(huì)接收到回調(diào)。相關(guān)邏輯與反向Binding相關(guān),谷歌官方還沒給出相關(guān)使用文檔,不再深入分析;

  • super.requestRebind()

1.此函數(shù)為ViewDataBinding中的函數(shù),具體實(shí)現(xiàn)為判斷現(xiàn)在是否有Rebind請求,如果有則return;如果沒有則根據(jù)運(yùn)行時(shí)sdk版本交給handler或者choreographer插入到下一幀中執(zhí)行mRebindRunnable。

2.在mRebindRunnable中會(huì)根據(jù)當(dāng)前sdk版本,如果大于等于KITKAT,則需要在onAttachToWindow后執(zhí)行executePendingBindings;否則直接執(zhí)行executePendingBindings。 

 

3.在父類ViewDataBinding中經(jīng)過一些的判斷,調(diào)用到ActivityDetail3Binding中的executeBindings,在executeBindings中根據(jù)dirtyFlags執(zhí)行不同的View屬性賦值,以下所有ActivityDetail3Binding相關(guān)代碼都是編譯器自動(dòng)生成的

  1. public class ActivityDetail3Binding extends ViewDataBinding{ 
  2.   ...  protected void executeBindings() {      long dirtyFlags = 0L;      synchronized(this) { 
  3.           dirtyFlags = this.mDirtyFlags;          this.mDirtyFlags = 0L; 
  4.       } 
  5.  
  6.       Drawable avatarAdapter = null
  7.       ModelAdapter adapter = this.mAdapter; 
  8.       String descAdapter = null
  9.       String nameAdapter = null
  10.       ActivityDetail3Binding.OnClickListenerImpl androidViewViewOnCli = null
  11.       String actionTextAdapter = null;      int visibility = this.mVisibility;      if((dirtyFlags & 5L) != 0L && adapter != null) { 
  12.           avatarAdapter = adapter.getAvatar(); 
  13.           descAdapter = adapter.getDesc(); 
  14.           nameAdapter = adapter.getName(); 
  15.           androidViewViewOnCli = (this.mAndroidViewViewOnCl == null?(this.mAndroidViewViewOnCl = new ActivityDetail3Binding.OnClickListenerImpl()):this.mAndroidViewViewOnCl).setValue(adapter); 
  16.           actionTextAdapter = adapter.actionText(); 
  17.       }      if((dirtyFlags & 6L) != 0L) { 
  18.           ; 
  19.       }      if((dirtyFlags & 5L) != 0L) { 
  20.           TextViewBindingAdapter.setText(this.detailActionButton, actionTextAdapter);          this.detailActionButton.setOnClickListener(androidViewViewOnCli); 
  21.           ImageViewBindingAdapter.setImageDrawable(this.detailAvatar, avatarAdapter); 
  22.           TextViewBindingAdapter.setText(this.detailDesc, descAdapter); 
  23.           TextViewBindingAdapter.setText(this.detailName, nameAdapter); 
  24.       }      if((dirtyFlags & 6L) != 0L) {          this.detailAvatar.setVisibility(visibility);          this.detailDesc.setVisibility(visibility);          this.detailName.setVisibility(visibility); 
  25.       } 
  26.  
  27.   } 
  28.   ... 

至此,完成了View數(shù)據(jù)的填充分析。

4 Binding

自動(dòng)生成的ViewDataBinding類(例如ActivityDetail3Binding)內(nèi)包含了Model + View,是MVVM中的MV的概念。

第2章的View注入,第3章的View賦值都是鋪墊,他們最后都是為Binding操作進(jìn)行服務(wù)。目前谷歌已經(jīng)支持雙向Binding,但上文已經(jīng)提到,目前資料比較少。本文只關(guān)注單向的Binding,即:Model的變化,自動(dòng)同步到View上。

4.1 使用ObservableField

目前所提供的ObservableField有:

Observable類型 對應(yīng)原類型
ObservableArrayList ArrayList
ObservableArrayMap ArrayMap
ObservableBoolean boolean
ObservableByte byte
ObservableChar char
ObservableFloat float
ObservableDouble double
ObservableLong long
ObservableInt int
ObservableParcelable<T extends Parcelable> <T extends Parcelable>
ObservableField<T> <T>

本文使用簡單的ObservableInt作為示例,解決visibility的單項(xiàng)綁定問題。

  • 改造activity_detail4.xml:定義類型為ObservableInt的variable,name為visibility,隨后賦值給ImageView的android:visibility,示例如下: 
  1. <layout xmlns:android="http://schemas.android.com/apk/res/android"
  2.   <data> 
  3.       <variable name="visibility" type="android.databinding.ObservableInt"/> 
  4.   </data> 
  5.   <LinearLayout 
  6.       android:orientation="vertical" android:layout_width="match_parent" 
  7.       android:layout_height="match_parent"
  8.      ...      <ImageView 
  9.           android:visibility="@{visibility.get()}" 
  10.           android:id="@+id/detail_avatar" 
  11.           android:layout_gravity="center" 
  12.           android:layout_marginTop="-33dp" 
  13.           android:layout_width="66dp" 
  14.           android:layout_height="66dp" /> 
  15.       ...  </LinearLayout></layout>  
  • 改造DetailActivity4.java,只需要在onCreate時(shí)把visibility賦值給binding(ActivityDetail4Binding)即可,后面對visibility的操作,就會(huì)更新到view上,示例代碼如下: 
  1. public class DetailActivity4 extends AppCompatActivity { 
  2.   ActivityDetail4Binding binding; 
  3.   ObservableInt visibility = new ObservableInt();  @Override 
  4.   protected void onCreate(@Nullable Bundle savedInstanceState) {      super.onCreate(savedInstanceState); 
  5.       binding = DataBindingUtil.setContentView(this,R.layout.activity_detail4,new MyComponent()); 
  6.       binding.setVisibility(visibility); 
  7.       login(); 
  8.   }  private void login(){  fill(User.newInstance());  }  private void logout(){ fill(null); }  private void fill(final User user){ 
  9.       visibility.set(user != null ? View.VISIBLE : View.GONE); 
  10.       .... 
  11.   } 
  12.   .... 
  13.  

4.2 ActivityDetail4Binding中單向綁定相關(guān)的代碼分析

與給ActivityDetail4Binding直接set純Model不同,所有的ObservableField都實(shí)現(xiàn)了Observable接口,只要實(shí)現(xiàn)了Observable接口,都是單向Binding類型,所以ActivityDetail4Binding中的setVisibility多加了一行代碼:this.updateRegistration(1, visibility),其中1為propertyId,目前一共自動(dòng)生成了2個(gè),0為adatper,1為visibility,代碼如下:

  1. public class ActivityDetail4Binding extends ViewDataBinding { 
  2.     ...    public void setVisibility(ObservableInt visibility) {        this.updateRegistration(1, visibility);        this.mVisibility = visibility;        synchronized(this) {            this.mDirtyFlags |= 2L; 
  3.         }        this.notifyPropertyChanged(3);        super.requestRebind(); 
  4.     } 
  5.     ... 

updateRegistration函數(shù)為ViewDataBinding中的函數(shù),會(huì)根據(jù) Observable、ObservableList、ObservableMap三種類型,分別創(chuàng)建對應(yīng)的Listener。ObservableInt為Observable,所以會(huì)使用CREATE_PROPERTY_LISTENER,在registerTo函數(shù)中創(chuàng)建WeakPropertyListener,

代碼如下: 

  1. public abstract class ViewDataBinding extends BaseObservable { 
  2.     ...    private boolean updateRegistration(int localFieldId, Object observable, 
  3.             CreateWeakListener listenerCreator) {        if (observable == null) {            return unregisterFrom(localFieldId); 
  4.         } 
  5.         WeakListener listener = mLocalFieldObservers[localFieldId];        if (listener == null) { 
  6.             registerTo(localFieldId, observable, listenerCreator);            return true
  7.         }        if (listener.getTarget() == observable) {            return false;//nothing to do, same object 
  8.         } 
  9.         unregisterFrom(localFieldId); 
  10.         registerTo(localFieldId, observable, listenerCreator);        return true
  11.     } 
  12.     ... 
  13.  

在WeakPropertyListener的mListener有個(gè)setTarget函數(shù),這個(gè)函數(shù)會(huì)向mObservable(即外面?zhèn)鬟M(jìn)來的visibility)注冊一個(gè)監(jiān)聽器,如果visibility值發(fā)生變化,這個(gè)listener就會(huì)得到通知,回調(diào)到WeakPropertyListener的onPropertyChanged,接著通知到binding(ActivityDetail4Binding)的handleFieldChange,在handleFieldChange中調(diào)用了ActivityDetail4Binding的onFieldChange函數(shù),如果返回值為true,則在handleFieldChange中調(diào)用requestRebind(),通知View進(jìn)行賦值更新界面,onFieldChange相關(guān)代碼如下:

  1. public abstract class ViewDataBinding extends BaseObservable { 
  2.     ...   private void handleFieldChange(int mLocalFieldId, Object object, int fieldId) {        boolean result = onFieldChange(mLocalFieldId, object, fieldId);        if (result) { 
  3.             requestRebind(); 
  4.         } 
  5.     } 
  6.     ... 
  7.  
  1. public class ActivityDetail4Binding extends ViewDataBinding { 
  2.     ...    protected boolean onFieldChange(int localFieldId, Object object, int fieldId) {        switch(localFieldId) {        case 0:            return this.onChangeAdapter((ModelAdapter)object, fieldId);        case 1:            return this.onChangeVisibility((ObservableInt)object, fieldId);        default:            return false
  3.         } 
  4.     } 
  5.     ... 

4.3 Observable Objects

與4.1 ObservableField類似,可以改造一下ModelAdapter:為getter方法增加@Bindable注解,為setter方法增加notifyPropertyChanged(com.asha.demo.BR.name)通知。其中,BR是根據(jù)@Bindalbe自動(dòng)生成的類,給getter方法增加@Bindable注解后,BR文件自動(dòng)會(huì)生成一個(gè)整型的name。改造后代碼如下:

  1. public class DetailActivity4 extends AppCompatActivity { 
  2.  
  3.     ActivityDetail4Binding binding; 
  4.     ObservableInt visibility = new ObservableInt();    public class ModelAdapter extends BaseObservable{        private User user;        public ModelAdapter(User user) {            this.user = user
  5.         } 
  6.         ...        @Bindable 
  7.         public String getName(){            return user != null ? user.getName() : null
  8.         }        public void setName(String name){            if (user != nulluser.setName(name); 
  9.             notifyPropertyChanged(com.asha.demo.BR.name); 
  10.         } 
  11.         ... 
  12.     } 
  13.     ... 

 隨后,在DetailActivity4.java中調(diào)用測試代碼,執(zhí)行完會(huì)在1秒后改變adapter上的name值,并且同步到View上,測試代碼如下:

  1. binding.detailActionButton.postDelayed(new Runnable() {    @Override 
  2.     public void run() { 
  3.         adapter.setName("haha"); 
  4.     } 
  5. },1000);  

具體原理與4.1類似,不再贅述。

5 layout.xml中View屬性的setter

在下述示例中,detail_name這個(gè)TextView想把a(bǔ)dapter.name賦值給自身的text屬性,就需要調(diào)用textView.setText(String)方法,這個(gè)方法就是View屬性的setter方法。

  1. <TextView 
  2.     android:text="@{adapter.name}" 
  3.     android:id="@+id/detail_name" 
  4.     android:layout_width="wrap_content" 
  5.     android:layout_height="wrap_content" />  

5.1 @BindingAdapter

上述的setter方法,Data Binding庫幫我們實(shí)現(xiàn)了大部分默認(rèn)方法,具體方法參見android.databinding.adapters包下的類,下圖為ViewBindingAdatper具體實(shí)現(xiàn),

 

ViewBindingAdatper

其中setter方法都為static方法,第一個(gè)參數(shù)都為自身的實(shí)例,后面為xml中傳入的參數(shù),只要加入@BindingAdapter注解,編譯器就會(huì)全局搜索保存在一個(gè)temp文件中,并在生成類似ActivityDetail4Binding過程中去查找所需的setter方法的。如果需要自定義,只需要在任意app代碼中定義@BindingAdapter即可,例如:

  1. public class DetailActivity4 extends AppCompatActivity {    @BindingAdapter("android:alpha")    public static void globalSetAlpha(View viewfloat alpha) { 
  2.         view.setAlpha(alpha); 
  3.     } 
  4.  

5.2 DataBindingComponent

很多情況下只是某個(gè)Binding文件(例如ActivityDetail4Binding)需要自定義setter方法,這個(gè)時(shí)候就需要使用DataBindingComponent,

  • 首先,定義一個(gè)MyComponent,
  1. public class MyComponent implements android.databinding.DataBindingComponent {  @BindingAdapter("android:alpha")  public void setAlpha(View viewfloat alpha) { 
  2.       view.setAlpha(0.5f); 
  3.   }  @Override 
  4.   public MyComponent getMyComponent() {      return new MyComponent(); 
  5.   } 
  6.  
  • 接著,在生成Binding對象時(shí)傳入這個(gè)DataBindingComponent實(shí)例,代碼如下:
  1. @Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {  super.onCreate(savedInstanceState); 
  2.   binding = DataBindingUtil.setContentView(this,R.layout.activity_detail4,new MyComponent()); 
  3.   ... 
  4.  

完成后,這個(gè)ActivityDetail4Binding范圍內(nèi)的所有android:alpha="@{foo}"的方式賦值alpha的setter函數(shù)都會(huì)使用MyComponent#setAlpha。

5.3 @BindingConversion

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

  • 1.定義一個(gè)靜態(tài)函數(shù),放在項(xiàng)目任意類中, 
  1. @BindingConversionpublic static Drawable convertColorToDrawable(int drawable) {  return new ColorDrawable(drawable); 
  2.  
  • 2.在layout.xml中使用Data Binding,如:
  1. <Viewandroid:background="@{adapter.avatar != null ? @color/detail_background : @color/colorAccent }"android:layout_width="match_parent"android:layout_height="66dp"

對應(yīng)在ActivityDetail4Binding.java中生成的代碼如下所示,其中AvatarAdapterObjectn1為int類型: 

  1. ViewBindingAdapter.setBackground(this.mboundView1, DetailActivity4.convertColorToDrawable(AvatarAdapterObjectn1)); 

5.4 @BindingMethod

例如layout.xml中android:onClick屬性,在Binding中真正使用setter時(shí),就對應(yīng)到了setOnClickListener方法,

  1. @BindingMethod(type = View.class, attribute = "android:onClick", method = "setOnClickListener"), 

6 Data Binding利用編譯器在背后做的那些事兒

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所依賴

為了提高運(yùn)行時(shí)的效率,Data Binding在背后做了非常多的工作,下圖是我整理的編譯流程,如圖所示:

 

Data Binding編譯流程

6.1 相關(guān)對象介紹

  • 白色部分為輸入,包括

1.res/layout;

2.源代碼中的注解;

  • 黃色部分為編譯器處理類,包括

1.aapt編譯時(shí)處理,入口類名為MakeCopy.java;

2.gradle-api處理,入口類名為DataBinderPlugin.java;

3.AbstractProcessor處理,入口類名為ProcessDataBinding.java;

  • 藍(lán)色部分為中間產(chǎn)物,包括

1.data-binding-info文件夾,包含了layout的基本信息,導(dǎo)入的變量,View標(biāo)簽中的表達(dá)式,標(biāo)簽的位置索引等等,如下所示為data-binding-info/activity_detail3-layout.xml: 

 

2.setter_store.bin,包含所有setter相關(guān)信息;

3.layoutinfo.bin,包含所有l(wèi)ayout相關(guān)信息;

4.br.bin,包含所有BR相關(guān)信息;

以上bin文件都以Serializable方式序列化到磁盤上,需要的時(shí)候進(jìn)行反序列化操作;

  • 綠色部分為最終產(chǎn)物,包括

1.data-binding-layout-out(最終輸出到res/layout),即去掉根節(jié)點(diǎn)<layout>,去掉節(jié)點(diǎn)<data>,與不使用Data Binding時(shí)的layout相一致,例如data-binding-layout-out/activity_detail2.xml:

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <LinearLayout 
  3.   android:orientation="vertical" android:layout_width="match_parent" 
  4.   android:layout_height="match_parent" android:tag="layout/activity_detail2_0" xmlns:android="http://schemas.android.com/apk/res/android"
  5.   <View 
  6.       android:background="@color/detail_background" 
  7.       android:layout_width="match_parent" 
  8.       android:layout_height="66dp"
  9.   </View
  10.   ... 
  11. </LinearLayout>  

2.DataBindingInfo.class,一個(gè)看似空的類,但在SOURCE階段包含了一個(gè)@BindingBuildInfo注解,包含了基本DataBinding的基本信息,代碼如下:

  1. // DataBindingInfo.classpublic class DataBindingInfo {  public DataBindingInfo() { 
  2.   } 
  3. }// @BindingBuildInfo@Target({ElementType.TYPE})@Retention(RetentionPolicy.SOURCE)public @interface BindingBuildInfo {  String buildId();  String modulePackage();  String sdkRoot();  int minSdk();  String layoutInfoDir();  String exportClassListTo();  boolean isLibrary();  boolean enableDebugLogs() default false;  boolean printEncodedError() default false

 3.DataBindingComponent.class,會(huì)根據(jù)自定義的DataBindingComponent自動(dòng)生成對應(yīng)實(shí)例化方法,例如:

  1. public interface DataBindingComponent { MyComponent getMyComponent(); 
  2.  
  3.  

4.ViewDataBinding.class的子類(ActivityDetail2Binding.class等)

5.BR.class,Bindable屬性索引表,例如:

  1. public class BR {  public static final int _all = 0;  public static final int adapter = 1;  public static final int name = 2;  public static final int visibility = 3;  public BR() { 
  2.   } 
  3.  

6.DataBindingMapper.class,Mapper,用于尋找某個(gè)layout.xml對應(yīng)的ViewDataBinding類,例如:

  1. class DataBinderMapper {  static final int TARGET_MIN_SDK = 16;  public DataBinderMapper() { 
  2.   }  public ViewDataBinding getDataBinder(DataBindingComponent bindingComponent, View viewint layoutId) {      switch(layoutId) {      case 2130968602:          return ActivityDetail2Binding.bind(view, bindingComponent);      case 2130968603:          return ActivityDetail3Binding.bind(view, bindingComponent); 
  3.      ....      default:          return null
  4.       } 
  5.   }  ViewDataBinding getDataBinder(DataBindingComponent bindingComponent, View[] views, int layoutId) {      return null
  6.   }  int getLayoutId(String tag) {      if(tag == null) {          return 0; 
  7.       } else {          int code = tag.hashCode();          switch(code) {          case -600937657:              if(tag.equals("layout/activity_detail2_0")) {                  return 2130968602; 
  8.               }              break;          case -600936696:              if(tag.equals("layout/activity_detail3_0")) {                  return 2130968603; 
  9.               }              break; 
  10.           ....          return 0; 
  11.       } 
  12.   }  String convertBrIdToString(int id) {      return id >= 0 && id < DataBinderMapper.InnerBrLookup.sKeys.length?DataBinderMapper.InnerBrLookup.sKeys[id]:null
  13.   }  private static class InnerBrLookup {      static String[] sKeys = new String[]{"_all""adapter""name""visibility"};      private InnerBrLookup() { 
  14.       } 
  15.   } 

6.2 相關(guān)編譯流程

  • STEP1 資源處理

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

  • STEP2 DataBindingInfo.class生成

在完成資源處理后,aapt或者gradle-api都會(huì)去執(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)會(huì)按順執(zhí)行3步,ProcessMethodAdapter,ProcessExpressions,ProcessBindable。每次執(zhí)行都會(huì)從磁盤反序列化對應(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更新;

7 細(xì)節(jié)補(bǔ)充-View Tag的使用

第二章有講到View是如何注入的,其實(shí)需要分兩種情況:

  • 1.如果這個(gè)View標(biāo)簽屬性中只有id,沒有其他"@{表達(dá)式}"形式,則按照第2章提到的方式直接通過id查找;
  • 2.如果這個(gè)View標(biāo)簽屬性中有"@{表達(dá)式}"形式的值,則編譯器會(huì)自動(dòng)給這個(gè)View加個(gè)android:tag="binding_{N}", 其中{N}按順序從0開始遞增,如android:tag="binding_0"。當(dāng)執(zhí)行ViewDataBinding#mapBindings去注入View時(shí),會(huì)找tag為binding_開頭的View,隨后執(zhí)行View注入;

另外,如果View標(biāo)簽原來就有android:tag值,則編譯器會(huì)先保存原有值信息,寫入android:tag="binding_{N}"。當(dāng)執(zhí)行完view注入后,再把原來的值賦值給android:tag。注意如果原來的android:tag值為"binding_0",那么在View注入時(shí)將會(huì)發(fā)生錯(cuò)亂。

在完成View注入后,ActivityDetail3Binding會(huì)執(zhí)行this.setRootTag(root),代碼如下:

 

這與ListView中的ViewHoloder實(shí)現(xiàn)方式相似,所以如果把DataBinding運(yùn)用到ListView的ViewHolder中,就不需要多生成一個(gè)ViewHolder,直接使用這個(gè)ViewDataBinding類即可,例如ListAdapter實(shí)現(xiàn):

 

8 總結(jié)

  • DataBinding 庫非常小

目前Android Data Binding在運(yùn)行類庫只有632個(gè)方法數(shù),算上每個(gè)layout.xml自動(dòng)生成的ViewDataBinding子類(demo中每個(gè)類不超過20個(gè)方法數(shù)),方法數(shù)總和也非常有限。

 

Data Binding方法數(shù)

  • DataBinding 運(yùn)行時(shí)沒有多余性能損耗

DataBinding所有的View注入、View賦值、Binding都是編譯器自動(dòng)生成的代碼,這些重復(fù)的體力勞動(dòng)本身就需要去做,只是交給了編譯器來完成,所以運(yùn)行時(shí)沒有多余的性能損耗。

  • DataBinding 可以減少錯(cuò)誤率

既然View注入、View賦值、Binding都是編譯器自動(dòng)完成的,只要使用正確,100%無低級錯(cuò)誤保證,可以提高代碼質(zhì)量,讓開發(fā)者心情愉悅。

  • DataBinding 對編譯時(shí)長的影響

還沒實(shí)際運(yùn)用到生產(chǎn)環(huán)境,肯定有所延長,具體量級還未知。 

責(zé)任編輯:龐桂玉 來源: Android技術(shù)之家
相關(guān)推薦

2011-09-16 09:06:20

Smalltalk

2011-03-31 14:22:28

Chrome插件

2016-05-05 10:54:53

Android開發(fā)應(yīng)用

2011-05-12 09:12:16

Ubuntu 11.0

2021-01-18 09:55:46

Spring代碼Java

2010-12-08 09:59:10

CSS

2021-02-02 21:42:30

VS Code編輯器開發(fā)

2021-04-13 10:07:08

Python軟件包編程語言

2009-08-29 08:41:07

Windows 7新功能

2021-04-25 10:15:38

Python編程語言軟件包

2021-01-24 11:55:40

spring升華代碼的技巧開發(fā)

2023-07-04 08:19:25

IDEA插件

2020-11-03 15:10:55

Spring Batc框架Java

2011-04-19 09:08:09

web工具項(xiàng)目管理

2023-07-18 08:46:34

開發(fā)必備軟件工具

2013-05-06 22:52:10

智能手機(jī)交互方式用戶體驗(yàn)

2021-01-20 06:29:42

JS工具操作符

2021-12-09 13:30:17

微軟

2024-12-17 15:00:00

Python代碼

2011-02-17 09:29:45

WebjQueryJavascript
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

欧美人与禽猛交乱配| jlzzjlzzjlzz亚洲人| 免费黄色成人| 精品视频一区三区九区| 中文字幕一区综合| 凸凹人妻人人澡人人添| 蜜臀久久99精品久久久久宅男| 久久国产精品久久久久久久久久| 欧亚乱熟女一区二区在线| 欧美最新精品| 亚洲风情在线资源站| 日韩三级电影免费观看| 国精产品一品二品国精品69xx| 久久精品人人| 欧美老少配视频| 你懂得视频在线观看| av毛片精品| 欧美日韩国产美| 日本网站免费在线观看| a黄色片在线观看| 2021中文字幕一区亚洲| 成人欧美一区二区| 国产又粗又猛又爽| 欧美亚洲一区二区三区| 欧美大荫蒂xxx| 在线免费看视频| 伊人久久大香线蕉无限次| 欧美大黄免费观看| 日韩av加勒比| 91另类视频| 色就色 综合激情| 免费国产黄色网址| 肉肉视频在线观看| 亚洲美女一区二区三区| 一区二区日本伦理| 高清中文字幕一区二区三区| 91视频com| 99理论电影网| 国内老熟妇对白hdxxxx| 久久国产人妖系列| 国产精品一区av| 中文字幕免费高清网站| 美女日韩在线中文字幕| 国内精品久久久久久中文字幕| 老湿机69福利| 亚洲成人精品| 久久精品视频导航| 亚洲AV成人无码精电影在线| 久久精品国产99久久| 中文字幕日韩欧美在线| 成人国产精品久久久网站| 九一成人免费视频| 亚洲精品第一页| 91丝袜在线观看| 另类ts人妖一区二区三区| 亚洲第一天堂av| 国产精品无码永久免费不卡| 欧美a级网站| 精品亚洲精品福利线在观看| 艳妇乳肉豪妇荡乳xxx| 国产精品videossex| 亚洲国产另类久久精品| xxxx黄色片| 亚洲精品亚洲人成在线观看| 亚洲欧美国产一区二区三区| 欧美做受喷浆在线观看| 国产成人1区| 中文字幕无线精品亚洲乱码一区| 色婷婷粉嫩av| 亚洲欧美一级二级三级| 欧美富婆性猛交| 日韩精品视频免费播放| 久久国产免费| 国产这里只有精品| 成人h动漫精品一区二区无码| 国产成人亚洲综合a∨婷婷图片| 成人在线资源网址| 日本在线丨区| 中文字幕电影一区| 免费的av在线| 欧美aa在线| 欧美丝袜丝交足nylons| 一卡二卡三卡四卡五卡| 欧美a大片欧美片| 中文字幕亚洲精品| 精品97人妻无码中文永久在线| 狠狠干综合网| 国产成人一区二区三区| 国产精品自产拍| 国产精品一卡二卡在线观看| 久久国产手机看片| 在线观看美女网站大全免费| 亚洲精选在线视频| 黄色片视频在线免费观看| 粉嫩av一区二区三区四区五区| 欧美一级精品在线| 亚洲天堂久久新| 日韩理论电影院| 欧美精品videosex性欧美| 黑人一级大毛片| 精品一区二区三区在线播放| 韩日午夜在线资源一区二区| 午夜激情视频在线观看| 激情成人中文字幕| 亚洲一二三不卡| 亚州av一区| 久久国产精品网站| 波多野结衣啪啪| 国产精品一级黄| 日韩免费av电影| 91桃色在线观看| 欧美日韩成人综合天天影院| 国产美女视频免费观看下载软件| 婷婷久久一区| 日韩美女毛茸茸| 亚洲欧美激情在线观看| 国产精品污污网站在线观看| 免费国产a级片| 日韩精品中文字幕一区二区| 亚洲人成在线观| 黑人精品一区二区| 免费一区二区视频| 国产女主播一区二区三区| 超碰在线影院| 午夜影院在线观看欧美| www.欧美激情.com| 日本a级不卡| 91黑丝高跟在线| xxxx国产精品| ...中文天堂在线一区| 美女喷白浆视频| 婷婷综合成人| 久久久伊人欧美| 99热精品在线播放| 国产精品理伦片| jizz欧美激情18| 综合干狼人综合首页| 高清一区二区三区四区五区| 国产男女裸体做爰爽爽| 中文在线一区二区| 999在线免费视频| 偷拍精品福利视频导航| 97在线日本国产| 国内爆初菊对白视频| 一区二区三区精品在线观看| caoporm在线视频| 欧美jizz| 国产精品毛片a∨一区二区三区|国 | aaa在线视频| 久久免费电影网| 国产免费人做人爱午夜视频| 亚洲香蕉视频| 国产精品99久久久久久人| 国产黄色片在线观看| 欧美午夜精品免费| 成人欧美一区二区三区黑人一| 日日夜夜精品视频免费| 日韩精品一区二区三区色偷偷| 日韩免费福利视频| 国产一区二区三区中文 | 第四色日韩影片| 亚洲第一视频在线观看| 亚洲第一精品在线观看| 久久影院视频免费| 91日韩视频在线观看| 99久久亚洲精品蜜臀| 18成人免费观看网站下载| 色呦呦网站在线观看| 亚洲国产精品电影| 亚洲视频 欧美视频| 国产精品情趣视频| 91人妻一区二区三区| 国户精品久久久久久久久久久不卡| 国产一区二区三区奇米久涩| 免费观看亚洲| 中文字幕日韩精品在线观看| 99热这里只有精| 好吊成人免视频| av片在线免费看| 成人中文字幕在线| 免费午夜视频在线观看| 国产精品久久久久久久久久10秀| 成人资源av| 日日av拍夜夜添久久免费| 久久久精品一区| 天天干天天爽天天操| 欧美亚洲动漫精品| 99视频只有精品| 久久欧美一区二区| 国产高清999| 亚洲少妇一区| 婷婷视频在线播放| 亚洲区小说区图片区qvod按摩| 国产精品久久久久久久久久久久久久| 黄视频在线观看网站| 精品成人在线观看| 丰满熟女人妻一区二区三| 一区二区三区在线免费播放 | 99在线无码精品入口| 欧美日韩激情网| 久久国产波多野结衣| 久久综合色播五月| 男插女视频网站| 欧美综合国产| 精品国产一区二区三区无码| 欧美精选视频在线观看| 国模精品娜娜一二三区| 91成人精品观看| 国产97在线视频| av在线最新| 久久99国产综合精品女同| 成人77777| 亚洲欧美日韩天堂| 少妇荡乳情欲办公室456视频| 欧美日韩免费观看一区三区| 久久亚洲天堂网| 一区二区三区免费在线观看| 婷婷丁香综合网| 国产视频亚洲色图| 国产精品无码网站| 成人h动漫精品一区二区| 色一情一区二区| 日本欧美在线看| 成人黄色片视频| 亚洲国产专区校园欧美| 少妇高潮大叫好爽喷水| 青青草综合网| 欧美日韩高清在线一区| 国产一区二区三区亚洲| av一区二区三区免费| 99亚洲男女激情在线观看| 国产精品黄页免费高清在线观看| 婷婷电影在线观看| 欧美精品一区三区| 最新国产露脸在线观看| 久久精品国产2020观看福利| 成人免费黄色网页| 国产午夜精品全部视频播放| 青青草在线播放| 日韩二区三区在线| 少妇精品高潮欲妇又嫩中文字幕 | 国产精品高清网站| 成人直播视频| 国产成人精品久久二区二区| 久久uomeier| 国产97在线观看| 成人看片网站| 国产精品久久在线观看| 欧美日一区二区三区| 国产精品精品久久久| 91av一区| 成人欧美在线观看| 国产精品毛片无码| 99高清视频有精品视频| 999国产精品一区| 国产精品一区二区av| 女仆av观看一区| 奇米视频888战线精品播放| 欧美一区二区三区激情视频 | 日本欧美在线视频免费观看| www.国产一区| 91麻豆免费在线视频| 欧美—级a级欧美特级ar全黄| a√中文在线观看| 2018日韩中文字幕| 亚洲伦理影院| 91免费在线视频| 北条麻妃一区二区三区在线| 久久精品日产第一区二区三区精品版 | 欧美污视频久久久| 日韩av在线中文字幕| 成人免费看片视频在线观看| 国产字幕视频一区二区| 午夜肉伦伦影院| 美女视频一区在线观看| 91香蕉国产线在线观看| 波多野结衣在线aⅴ中文字幕不卡| 私密视频在线观看| 中文字幕av资源一区| 欧美第一页在线观看| 亚洲福利电影网| 国产一级精品毛片| 日韩欧美国产小视频| 欧美高清成人| 精品国内自产拍在线观看| 超级碰碰不卡在线视频| 国产精品久久电影观看| 我要色综合中文字幕| 欧美日韩一区二| 91精品国产成人观看| 久久久久免费看黄a片app| 蜜臀国产一区二区三区在线播放| 欧美xxxx黑人| 国产日韩av一区二区| 欧美成人精品欧美一| 在线这里只有精品| 亚洲狼人综合网| 这里只有精品久久| sm性调教片在线观看| 成人国产亚洲精品a区天堂华泰| 国产精品中文字幕制服诱惑| 在线视频不卡国产| 午夜亚洲性色福利视频| 99视频在线观看视频| 国产日韩欧美精品在线| 精品无码m3u8在线观看| 欧美日韩综合色| 无码国产伦一区二区三区视频| 日韩在线观看精品| 在线人成日本视频| 动漫精品视频| 久久久久久免费视频| 国产免费成人在线| 成人妖精视频yjsp地址| а天堂中文在线资源| 色老汉一区二区三区| 免费观看国产视频| 久久人人爽人人爽爽久久| 亚洲欧美99| 欧美高清一级片| 西游记1978| 中文一区在线| 香蕉视频免费网站| 亚洲欧美一区二区视频| 一级片免费在线播放| 亚洲第一级黄色片| 日本在线视频网址| 亚洲va男人天堂| 欧美高清视频手机在在线| 一本色道无码道dvd在线观看| 99国产精品99久久久久久| 免看一级a毛片一片成人不卡| 欧美日本韩国一区二区三区视频| 精品推荐蜜桃传媒| 91高清免费视频| 极品一区美女高清| 大荫蒂性生交片| 国产成人自拍网| 真实国产乱子伦对白在线| 欧美人体做爰大胆视频| 久久久久久国产精品mv| 91视频久久| 欧美美女性视频| 国产精品美女www爽爽爽| 国产一级片免费在线观看| 亚洲人a成www在线影院| 欧美极品免费| 日韩精品另类天天更新| 日韩高清在线一区| 亚洲一级片在线播放| 精品视频1区2区3区| 77777影视视频在线观看| 国产在线高清精品| 亚洲国产不卡| 亚洲成人av免费观看| 一区二区三区91| 日日夜夜精品免费| 日本sm极度另类视频| 欧美日韩123| 中文字幕 欧美日韩| 亚洲人吸女人奶水| 肥臀熟女一区二区三区| 45www国产精品网站| 免费久久久久久久久| 中文字幕在线观看第三页| 中文字幕一区二区视频| 国产suv一区二区| 97在线精品视频| 国产一区二区区别| 日韩av影视大全| 亚洲国产精品欧美一二99| 黄色电影免费在线看| 国产欧美在线视频| 狠狠噜噜久久| 欧美日韩高清丝袜| 欧美一区二区三区在线观看| 国产精品69xx| 日韩精品无码一区二区三区| 国产一区二区在线视频| 日韩av电影网| 日韩在线观看高清| 久久中文字幕导航| 在线观看日本一区二区| 亚洲午夜电影网| 中文字幕日本在线| 国产精品免费看一区二区三区| 久久动漫亚洲| 欧美精品久久久久性色| 亚洲欧美日韩爽爽影院| 久久99成人| caopor在线视频| 伊人色综合久久天天| 深夜福利视频在线观看| 91色p视频在线| 亚洲欧美春色| 精品欧美一区二区久久久久| 亚洲精选在线观看| 欧美专区视频| 日韩一级片播放| 亚洲3atv精品一区二区三区|