DataBinding 開發(fā)知識匯總

https://github.com/LaxusJie/DataBindingSimple

Data binding 入坑筆記二進階篇之雙向綁定

https://www.cnblogs.com/longjunhao/p/5860353.html

https://academy.realm.io/cn/posts/data-binding-android-boyar-mount/ 英文翻譯(較全)

https://www.colabug.com/1197309.html? 使用@InverseBindingMethods實現(xiàn)反向綁定

https://blog.csdn.net/zhangphil/article/details/77839555? 使用@InverseBindingAdapter反向綁定



DataBinding框架使用的的環(huán)境要求:

1寸士、保證接入的項目gradle插件版本不低于1.5.0-alpha1:

classpath'com.android.tools.build:gradle:1.5.0'

2、在對應模塊(Module)的build.gradle文件添加如下配置

dataBinding {??

? ? ?enabledtrue

}

Databinding接入

一惕艳、布局文件

要使用Data Binding首先xml文件有了以下變化,他的根節(jié)點變成了layout尝偎,里面包含一個data節(jié)點和原根節(jié)點LinearLayout凿滤,其中這個data是用來綁定數(shù)據(jù)的拔创。

在data內可以利用variable聲明變量,里面有兩個屬性name和type涌哲,name是變量的名字胖缤,type是變量的類型。(這里的User是一個實體類阀圾,下面說)?

也可以把類型提出來用import導入 哪廓,基礎類型(java.lang包下的,比如String)可以直接使用稍刀,無需import撩独。

配置好布局文件后,IDE會根據(jù)xml文件的名稱自動生成一個DataBinding類用于數(shù)據(jù)綁定账月,命名規(guī)則如下

activity_main.xml-> ActivityMainBinding

如果不喜歡自動生成的Data Binding名综膀,我們可以自己來定義

? ? .........

class對應的就是生成的Data Binding名

二、(viewModle)POJO對象

POJO類對象User局齿,這種類型的對象具有從不改變的數(shù)據(jù)剧劝。在應用程序中,數(shù)據(jù)是一次讀取抓歼,此后從不更改讥此,這是很常見的。

public class User{

? public final String firstName;

? public final String lastName;

? public User(String firstName, String lastName) {

? ? ? this.firstName = firstName;

? ? ? this.lastName = lastName;?

? ? ?}

}

也可以使用JavaBean形式

public class User{

private final String firstName;

private final String lastName;

public User(String firstName, String lastName) {

?this.firstName = firstName;

?this.lastName = lastName;?

?}

? public String getFirstName() {

? ? ? ?returnthis.firstName;?

?}

? public String getLastName() {

? ?returnthis.lastName;

? }

}

修改Activity中的onCreate方法谣妻,

用DataBindingUtil.setContentView替代原來的setContentView方法從而實現(xiàn)數(shù)據(jù)綁定,創(chuàng)建user對象萄喳,

通過binding.setUser(user)從而實現(xiàn)數(shù)據(jù)填充。(此時還是自動填充蹋半,需要手動調用binding對象的setUser方法通binding對象更新view視圖)

private User user;

@Override

protected void onCreate(Bundle savedInstanceState) {

? ? ? ?super.onCreate(savedInstanceState);?

?? ? ? ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);? ? ?

? ? ? ?user =newUser("Laxus","J");?

?? ? ? binding.setUser(user);??

? }

此處可以多說一句他巨,binding的setUser()方法是根據(jù)布局文件中標簽在編譯時生成了一個方法,binding也是編譯時生成的一個類减江,這個方法就聲明在binding這個類中染突,并且還有對應的一個getUser方法。除此之外辈灼,binging里還有int age這個屬性的set份企,get方法;

前面說了巡莹,寫到這個一步已經可以將user對象的數(shù)據(jù)刷新到布局視圖中去了司志,但是需要手動調用setUser方法甜紫,那么怎樣才能在數(shù)據(jù)更新后自動更新到布局中而不用調用setUser方法呢?

Databing提供了一個Observable接口俐芯,實現(xiàn)此接口的的pojo類可以被Databing框架識別和管理棵介;為了方便,Databing框架已經為我們封裝了一個BaseObservable類吧史,里面幫我們已經封裝了好了基礎功能;

讓一個類繼承BaseObservable:

public class Student extends BaseObservable{

? private String name;

? privateString className;

? @Bindable

? public String getName() {

? ? return? name;??

? ?}

@Bindable

public String getClassName() {

return className;? ?

?}

public void setName(String name) {

this.name?= name;

notifyPropertyChanged(BR.name);

?}

public void setClassName(String className) {

? ? this.className = className;? ? ?

?? notifyPropertyChanged(BR.className);??

? }

}

BR是編譯階段生成的一個類唠雕,功能與 R.java 類似贸营,用?@Bindable標記過?getter方法會在BR中生成一個靜態(tài)常量池,所有Pojo類的屬性在這個BR都有唯一一個對應的BR.XX常量岩睁。

public class BR{

public? static? final int_all =0;

public? static? final? int className =1

}

在setter方法里我們需要用notifyPropertyChanged方法來更新對象钞脂。寫了這個notifyPropertyChanged方法,此時就可以不用之后再改變一個對象中的某一個屬性捕儒,就可以不用再調用binding對象的整個set方法冰啃;

還有另一種適用于POJO的寫法,這種寫法不需要繼承BaseObservable刘莹,不過每個成員變量都要new一個ObservableField對象阎毅。

public class Teacher{

public final? ?ObservableField name =newObservableField<>();

?public? final? ObservableField className = newObservableField<>();

? public? final? ObservableInt age =newObservableInt();

}

注意,這個類里面沒有set点弯、get方法扇调,不用寫,Databing已經做了處理抢肛,使用時在代碼中如下寫:

mTeacher.name.set("wang");

?mTeacher.className.set("Java");

而在布局文件中的使用方法與普通屬性寫法一樣狼钮;

DataBinding? 還準備了ObservableBoolean,ObservableByte,ObservableChar,ObservableShort,ObservableInt,ObservableLong,ObservableFloat,ObservableDouble, 以及ObservableParcelableObservableArrayMapObservableArrayList

逆向綁定

上邊已經講完了捡絮,數(shù)據(jù)改變引起視圖改變的單向綁定熬芜,下面說一下頁面中空間的內容改變如何引起數(shù)據(jù)改變;

如果想在用戶輸入的時候給一個pojo類的屬性賦值福稳,則需要用到@={}這個操作符

只比單向綁定時涎拉,在@和{}中間多了一個=,就變成了雙向綁定灵寺!

引申

我們引申兩點曼库,一是逆向綁定的原理和另一個用法,二略板,整個Databing的工作原理毁枯。

逆向綁定:

Databing在對頁面生成一個bing對象時,會根據(jù)這個布局頁面里的view生成一些代碼叮称,其中就包括了如下代碼:

// values

// listeners

// Inverse Binding Event Handlers

private android.databinding.InverseBindingListener mboundView1androidTextAttrChanged =

? ? ? ?new android.databinding.InverseBindingListener() {

? ? ? ? ? @Override

? ? ? ? ?public void onChange() {

// Inverse of?student.name

? ? ? ? ? // is student.setName((java.lang.String) callbackArg_0)

? ? ? ? java.lang.String callbackArg_0 = android.databinding.adapters.TextViewBindingAdapter.getTextString(mboundView1);? ? ? ? ? // localize variables for thread safety

? ? ? ? // student com.jie.databindingsimple.entity.Student student = mStudent;

//?student.name?java.lang.String studentName = null;

? ? ? ? ?// student != null

? ? ? ? if (student)!= null)) {

? ? ? ? ?student.setName(((java.lang.String) (callbackArg_0)));

? ? ? ? ?}

? ? ? }

?};

@InverseBindingAdapter(attribute = "android:text", event = "android:textAttrChanged")

? ?public static String getTextString(TextView view) {

? ? ? ? return view.getText().toString();

? ? }

@BindingAdapter(value?=?{"android:textAttrChanged"},?requireAll?=?false)??

?public?static?void?setAndroidTextAttrChanged(Textview textview,?InverseBindingListener?inverseBindingListener)?{?

? ? ? ? ? if?(inverseBindingListener?==?null)?{???

???????????Log.e("錯誤种玛!",?"InverseBindingListener為空!");??????

? ? ? ? ?}?else?{? ? ? ?// 觸發(fā)更新

? ? ? ? ? inverseBindingListener =inverseBindingListener 藐鹤;

? ? ? ?}????

??}??

先是Databing在編譯時根據(jù)布局文件在生成如上代碼,運行時當用戶改變了文本赂韵,觸發(fā)textview的text屬性的改變娱节,然后Databing根據(jù)text屬性找到了getTextString方法和上邊的的注解中的event,然后根據(jù)event中的android:textAttrChanged找到setAndroidTextAttrChanged方法祭示,并將mboundView1androidTextAttrChanged屬性設置進去肄满,而textview的相關監(jiān)聽中判斷InverseBindingListener!=null了质涛,就調用InverseBindingListener.onChange();????onChange方法找到getTextString方法獲取文本并設置給Pojo對象稠歉;以上的的代碼Databing已經幫我們寫好了,不過知道了這幾部原理汇陆,我們也可以定義自己view邏輯怒炸。具體參考:

https://www.colabug.com/1197309.html?使用@InverseBindingMethods實現(xiàn)反向綁定

https://blog.csdn.net/zhangphil/article/details/77839555使用@InverseBindingAdapter反向綁定。

我回頭看一下Observable接口:

package android.databinding;

public interface Observable {

? ? ? void? ? ?addOnPropertyChangedCallback(Observable.OnPropertyChangedCallback var1);

? ? ? void? ? ?removeOnPropertyChangedCallback(Observable.OnPropertyChangedCallback var1);

? ? ?public? abstract static class OnPropertyChangedCallback { public OnPropertyChangedCallback() { }

? ? ?public? ?abstract void onPropertyChanged(Observable var1, int var2); }

}

Observable接口中有一個addOnPropertyChangedCallback方法用來添加一個接收屬性改變的callback毡代,我可以在activity中這樣寫阅羹,

來監(jiān)聽到某個屬性的改變;

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

Student student = new Student();

binding.setStudent(student);

student.addOnPropertyChangedCallback(new Observable.OnPropertyChangedCallback() {

@Override

public void onPropertyChanged(Observable observable, int i) {

switch (i) {

case?BR.name:

? ? Toast.makeText(TwowayActivity.this, "name", Toast.LENGTH_SHORT).show();

? ? break;

? ? case BR.className:

? ? Toast.makeText(TwowayActivity.this, "classname", Toast.LENGTH_SHORT).show();

? ? break;

? ? ? ? }

? ? ?}

? });

}

目前雙向綁定僅支持如text教寂,checked捏鱼,year,month孝宗,hour穷躁,rating,progress等綁定因妇。其它的需要我們自定義问潭;

Databing原理

http://www.reibang.com/p/c41e7a597ac8

自定義用法

1、轉換器

類型轉換對view賦值時有些類型需要轉換婚被,例如:color 為int值 狡忙,

view.setBackground 需要的是drawable參數(shù),這個時候址芯,需要定義類型轉換灾茁,

@BindingConversion

public static ColorDrawable convertColorToDrawable(int color) {

? return new ColorDrawable(color);

}

注意這個方法必須是public static的,該方法可以定義在任何地方谷炸。

2北专、適配器 @BindAdapter

適配器開發(fā)中一個比較常見的場景就是使用ImageLoader進行加載圖片,在任何地方添加適配器代碼:

@BindingAdapter("android:src"旬陡,requireAll = false)

public static void setImageUrl(ImageView view, String url) {?

? ? ? Picasso.with(view.getContext()).load(url).into(view);

}

這個時候可以使用下面代碼進行數(shù)據(jù)綁定:當進行bind的時候拓颓,會自動調用適配器定義的函數(shù)。適配器也可以用來添加view的屬性描孟。比如我想在Textview中綁定long型的時間戳驶睦,并且按照一個格式顯示砰左。

@android.databinding.BindingAdapter(value = {"app:date", "app:format"}, requireAll = false)

public static void bindFormat(TextView view, String date, String format) {

? if (date == null) {

? ? ? return;

? }

SimpleDateFormat formatter;

if (format != null) {

? ? ? formatter = new SimpleDateFormat(format);

? }else {

? ? ? formatter = new SimpleDateFormat("yyyy-MM-dd");

? }

? ? ?Long timeStamp = Long.parseLong(date);

? ? ?view.setText(formatter.format(new Date(timeStamp)));

}

其中 requireAll = false表示當參數(shù)不全時,也會調用適配器函數(shù)场航,補全的參數(shù)會傳入空值缠导,所以要自己判斷。

關于ImageView的另一種用法:

@BindingAdapter(value={"android:src","placeHolder"},requireAll=false)

public static void setImageUrl(ImageViewview,Stringurl,intplaceHolder){

? RequestCreator requestCreator=Picasso.with(view.getContext()).load(url);

? ? ?if(placeHolder!=0){

? ? ? ? ? requestCreator.placeholder(placeHolder);

? ?}?

? ? ? requestCreator.into(view);

}

資源(Resources):

可以使用正常語法的表達式訪問資源:

[html]view plaincopy

android:padding=“@{large??@dimen/largePadding?:?@dimen/smallPadding}”??

android:padding="@{large? @dimen/largePadding : @dimen/smallPadding}"

格式字符串和復數(shù)可通過提供參數(shù)判斷:

[html]view plaincopy

android:text=“@{@string/nameFormat(firstName,?lastName)}”??

android:text=“@{@plurals/banana(bananaCount)}”??

android:text="@{@string/nameFormat(firstName, lastName)}"

android:text="@{@plurals/banana(bananaCount)}"

當復數(shù)需要多個參數(shù)時溉痢,所有參數(shù)都應通過:

[html]view plaincopy

??Have?an?orange??

??Have?%d?oranges??

android:text=“@{@plurals/orange(orangeCount,?orangeCount)}”??

? Have an orange

? Have %d oranges

android:text="@{@plurals/orange(orangeCount, orangeCount)}"

一些資源需要顯示類型判斷:

自動安裝(Automatic Setters)

對于一個屬性僻造,Data Binding 試圖找到 setAttribute 方法,與該屬性的 name space 并沒有什么關系孩饼,僅僅與屬性本身名稱有關

例如嫡意,有關 TextView 的 android:text 屬性的表達式會尋找一個 setText(String) 的方法,如果表達式返回一個 int,Data Binding會搜索的 setText(int) 方法捣辆,這里要注意:表達式要返回正確的類型,如果需要的話使用 casting此迅,Data Binding 任然會工作汽畴,即使沒有給定的名稱屬性存在,然后耸序,你可以通過 Data Binding 輕松地為任何 setter “創(chuàng)造”屬性忍些,例如,DrawerLayout 沒有任何屬性坎怪,但大量的 setters罢坝,你可以使用自動 setters 來使用其中的一個:

[html]view plaincopy

android:layout_width=“wrap_content”? ? ?

android:layout_height=“wrap_content”??

app:scrimColor=“@{@color/scrim}”??

app:drawerListener=“@{fragment.drawerListener}”/>??

? ? android:layout_width="wrap_content"

? ? android:layout_height="wrap_content"

? ? app:scrimColor="@{@color/scrim}"

? ? app:drawerListener="@{fragment.drawerListener}"/>

重命名 Setters(Renamed Setters)

一些有 Setters 的屬性按名稱并不匹配,對于這些方法搅窿,屬性可以通過 BindingMethods 注解相關聯(lián)嘁酿,還必須與一個包含BindingMethod 注解類相關聯(lián),每一個用于重命名的方法男应,例如 ?andorid:tin 屬性與 ?setImageTintList 相關聯(lián)闹司,而不與 setTint相關

[java]view plaincopy

@BindingMethods({??

@BindingMethod(type?=?“android.widget.ImageView”,??

attribute?=”android:tint”,??

method?=”setImageTintList”),??

})??

@BindingMethods({

? ? ? @BindingMethod(type = "android.widget.ImageView",

? ? ? ? ? ? ? ? ? ? ? attribute = "android:tint",

? ? ? ? ? ? ? ? ? ? ? method = "setImageTintList"),

})

上面的例子,開發(fā)者不太可能重命名編譯程序沐飘,Android 框架屬性已經實現(xiàn)了

泛型支持

? ?

? ? ">

">// 左尖括號需要轉義游桩,

include

自定義 Setters(Custom Setters)

有些屬性需要自定義綁定邏輯,例如耐朴,對于 android:paddingLeft 屬性并沒有相關的setter借卧,相反,setPadding (left筛峭、top铐刘、right、bottom)是存在滨达,一個帶有 BindingAdapter 注解的靜態(tài)綁定適配器方法允許開發(fā)者自定義 setter 如何對于一個屬性的調用

Android 的屬性已經創(chuàng)造了 BindingAdapters,舉例來說,對于 paddingLeft:

[java]view plaincopy

@BindingAdapter(“android:paddingLeft”)??

public?static?void?setPaddingLeft(View?view,?int?padding)?{??

???view.setPadding(padding,??

???????????????????view.getPaddingTop(),??

???????????????????view.getPaddingRight(),??

???????????????????view.getPaddingBottom());??

}??

@BindingAdapter("android:paddingLeft")

public static void setPaddingLeft(View view, int padding) {

? view.setPadding(padding,

? ? ? ? ? ? ? ? ? view.getPaddingTop(),

? ? ? ? ? ? ? ? ? view.getPaddingRight(),

? ? ? ? ? ? ? ? ? view.getPaddingBottom());

}

Binding 適配對其他定制類型非常有用续挟,例如,自定義 loader 可以用異步載入圖像

當有沖突時博个,開發(fā)人員創(chuàng)建的 Binding 適配器將覆蓋 Data Binding 默認適配器

你也可以創(chuàng)建可以接收多個參數(shù)的適配器:

[java]view plaincopy

@BindingAdapter({“bind:imageUrl”,?“bind:error”})??

public?static?void?loadImage(ImageView?view,?String?url,?Drawable?error)?{??

???Picasso.with(view.getContext()).load(url).error(error).into(view);??

}??

@BindingAdapter({"bind:imageUrl", "bind:error"})

public static void loadImage(ImageView view, String url, Drawable error) {

? Picasso.with(view.getContext()).load(url).error(error).into(view);

}

[html]view plaincopy

app:error=“@{@drawable/venueError}”/>??

app:error="@{@drawable/venueError}"/>

如果對于一個 ImageView imageUrl 和 error 都被使用蜒什,并且 imageUrl 是一個 String 類型以及 error 是一個 drawable 時着绊,該適配器被調用

匹配的過程中自定義 name spaces 將被忽略

你也可以為 Android name spaces 寫適配器

綁定適配器方法可以在其處理程序中選擇舊值。取舊值和新值的方法應具有所有屬性的舊值,其次是新值:

[java]view plaincopy

@BindingAdapter(“android:paddingLeft”)??

public?static?void?setPaddingLeft(View?view,?int?oldPadding,?int?newPadding)?{??

if?(oldPadding?!=?newPadding)?{??

???????view.setPadding(newPadding,??

???????????????????????view.getPaddingTop(),??

???????????????????????view.getPaddingRight(),??

???????????????????????view.getPaddingBottom());??

???}??

}??

@BindingAdapter("android:paddingLeft")

public static void setPaddingLeft(View view, int oldPadding, int newPadding) {

? if (oldPadding != newPadding) {

? ? ? view.setPadding(newPadding,

? ? ? ? ? ? ? ? ? ? ? view.getPaddingTop(),

? ? ? ? ? ? ? ? ? ? ? view.getPaddingRight(),

? ? ? ? ? ? ? ? ? ? ? view.getPaddingBottom());

? }

}

事件處理程序只能用一個抽象方法與接口或抽象類一起使用,例如:

[java]view plaincopy

@BindingAdapter(“android:onLayoutChange”)??

public?static?void?setOnLayoutChangeListener(View?view,?View.OnLayoutChangeListener?oldValue,??

???????View.OnLayoutChangeListener?newValue)?{??

if?(Build.VERSION.SDK_INT?>=?Build.VERSION_CODES.HONEYCOMB)?{??

if?(oldValue?!=?null)?{??

????????????view.removeOnLayoutChangeListener(oldValue);??

????????}??

if?(newValue?!=?null)?{??

????????????view.addOnLayoutChangeListener(newValue);??

????????}??

????}??

}??

@BindingAdapter("android:onLayoutChange")

public static void setOnLayoutChangeListener(View view, View.OnLayoutChangeListener oldValue,

? ? ? View.OnLayoutChangeListener newValue) {

? ? if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {

? ? ? ? if (oldValue != null) {

? ? ? ? ? ? view.removeOnLayoutChangeListener(oldValue);

? ? ? ? }

? ? ? ? if (newValue != null) {

? ? ? ? ? ? view.addOnLayoutChangeListener(newValue);

? ? ? ? }

? ? }

}

當監(jiān)聽器有多個方法時卜录,它必須被分割成多個監(jiān)聽器,例如嗦篱,View.OnAttachStateChangeListener 的方法有兩種:onViewAttachedToWindow() 和 onViewDetachedFromWindow()涵卵。然后坏晦,我們必須創(chuàng)建兩個接口來區(qū)分它們的屬性和處理程序:

[java]view plaincopy

@TargetApi(VERSION_CODES.HONEYCOMB_MR1)??

public?interface?OnViewDetachedFromWindow?{??

void?onViewDetachedFromWindow(View?v);??

}??

@TargetApi(VERSION_CODES.HONEYCOMB_MR1)??

public?interface?OnViewAttachedToWindow?{??

void?onViewAttachedToWindow(View?v);??

}??

@TargetApi(VERSION_CODES.HONEYCOMB_MR1)

public interface OnViewDetachedFromWindow {

? ? void onViewDetachedFromWindow(View v);

}

@TargetApi(VERSION_CODES.HONEYCOMB_MR1)

public interface OnViewAttachedToWindow {

? ? void onViewAttachedToWindow(View v);

}

因為改變一個監(jiān)聽器也會影響另一個,我們必須有三個不同的綁定適配器,一個為每個屬性和一個為兩者拾积,他們應該被設置:

[java]view plaincopy

@BindingAdapter(“android:onViewAttachedToWindow”)??

public?static?void?setListener(View?view,?OnViewAttachedToWindow?attached)?{??

setListener(view,null,?attached);??

}??

@BindingAdapter(“android:onViewDetachedFromWindow”)??

public?static?void?setListener(View?view,?OnViewDetachedFromWindow?detached)?{??

setListener(view,?detached,null);??

}??

@BindingAdapter({“android:onViewDetachedFromWindow”,?“android:onViewAttachedToWindow”})??

public?static?void?setListener(View?view,?final?OnViewDetachedFromWindow?detach,??

final?OnViewAttachedToWindow?attach)?{??

if?(VERSION.SDK_INT?>=?VERSION_CODES.HONEYCOMB_MR1)?{??

final?OnAttachStateChangeListener?newListener;??

if?(detach?==?null?&&?attach?==?null)?{??

newListener?=null;??

}else?{??

newListener?=new?OnAttachStateChangeListener()?{??

@Override??

public?void?onViewAttachedToWindow(View?v)?{??

if?(attach?!=?null)?{??

????????????????????????attach.onViewAttachedToWindow(v);??

????????????????????}??

????????????????}??

@Override??

public?void?onViewDetachedFromWindow(View?v)?{??

if?(detach?!=?null)?{??

????????????????????????detach.onViewDetachedFromWindow(v);??

????????????????????}??

????????????????}??

????????????};??

????????}??

final?OnAttachStateChangeListener?oldListener?=?ListenerUtil.trackListener(view,??

newListener,R.id.onAttachStateChangeListener);

if?(oldListener?!=?null)?{??

????????????view.removeOnAttachStateChangeListener(oldListener);??

????????}??

if?(newListener?!=?null)?{??

????????????view.addOnAttachStateChangeListener(newListener);??

????????}??

????}??

}??

@BindingAdapter("android:onViewAttachedToWindow")

public static void setListener(View view, OnViewAttachedToWindow attached) {

? ? setListener(view, null, attached);

}

@BindingAdapter("android:onViewDetachedFromWindow")

public static void setListener(View view, OnViewDetachedFromWindow detached) {

? ? setListener(view, detached, null);

}

@BindingAdapter({"android:onViewDetachedFromWindow", "android:onViewAttachedToWindow"})

public static void setListener(View view, final OnViewDetachedFromWindow detach,

? ? ? ? final OnViewAttachedToWindow attach) {

? ? if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB_MR1) {

? ? ? ? final OnAttachStateChangeListener newListener;

? ? ? ? if (detach == null && attach == null) {

? ? ? ? ? ? newListener = null;

? ? ? ? } else {

? ? ? ? ? ? newListener = new OnAttachStateChangeListener() {

? ? ? ? ? ? ? ? @Override

? ? ? ? ? ? ? ? public void onViewAttachedToWindow(View v) {

? ? ? ? ? ? ? ? ? ? if (attach != null) {

? ? ? ? ? ? ? ? ? ? ? ? attach.onViewAttachedToWindow(v);

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? @Override

? ? ? ? ? ? ? ? public void onViewDetachedFromWindow(View v) {

? ? ? ? ? ? ? ? ? ? if (detach != null) {

? ? ? ? ? ? ? ? ? ? ? ? detach.onViewDetachedFromWindow(v);

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? }

? ? ? ? ? ? };

? ? ? ? }

? ? ? ? final OnAttachStateChangeListener oldListener = ListenerUtil.trackListener(view,

newListener,?R.id.onAttachStateChangeListener);

? ? ? ? if (oldListener != null) {

? ? ? ? ? ? view.removeOnAttachStateChangeListener(oldListener);

? ? ? ? }

? ? ? ? if (newListener != null) {

? ? ? ? ? ? view.addOnAttachStateChangeListener(newListener);

? ? ? ? }

? ? }

}

上面的例子是比正常的稍微復雜肛度,因為 View 使用添加和刪除的監(jiān)聽者而不是為 View.OnAttachStateChangeListener 設置方法傻唾,android.databinding.adapters.listenerutil 類有助于保持跟蹤,他們可能會在綁定適配器刪除以前的 listener

https://blog.csdn.net/willba/article/details/71552525時間監(jiān)聽

事件綁定方式

監(jiān)聽方法調用控件常用的監(jiān)聽都可以用事件綁定來搞定承耿,比如以下這幾種

android:onClick

android:onLongClick

android:onTextChanged

其他事件同理

Lambda表達式

在xml中我們還可以應用lambda表達式來書寫

android:onClick="@{(view) -> activity.onTextClick(view)}"

統(tǒng)計一下事件監(jiān)聽表達的用法

由此可見事件監(jiān)聽綁定有很多種用法冠骄,我們在項目中最好統(tǒng)一規(guī)范應用其中一種,避免個性化

android:onClick="onTextClick"

android:onClick="@{(view) -> activity.onTextClick(view)}"

android:onClick="@{activity::onTextClick}"

android:onClick="@{activity.onTextClick}"

問題匯總:

直接 Binding

當一個 Variable 或 Observable 變化時加袋,binding 會在下一幀前被計劃要求改變凛辣,但是有很多次在 Binding 時必需立即執(zhí)行,要強制執(zhí)行职烧,使用 executePendingBindings() 方法

后臺線程

只要它不是一個集合扁誓,你可以在后臺中改變數(shù)據(jù)模型,在判斷是否要避免任何并發(fā)問題時蚀之,Data Binding 會對每個 Variable/field本地化

線程問題

無論在子線程還是主線程中更新ViewModle數(shù)據(jù)蝗敢,Binding框架在更新Ui時都是將交給主線更關心uI,通常來說不會需要我們再做同步的事情足删,但是如果是RecycleView寿谴,則需要再UI線程中更新數(shù)據(jù),因為列表在滑動過程中不斷binging新Item失受,UI線程會不斷讀取viewModle中的數(shù)據(jù)(get方法)讶泰,如果此時再子線程更新了uI線程正在讀取的數(shù)據(jù)容易出現(xiàn)線程問題。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末拂到,一起剝皮案震驚了整個濱河市峻厚,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌谆焊,老刑警劉巖惠桃,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡辜王,警方通過查閱死者的電腦和手機劈狐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來呐馆,“玉大人肥缔,你說我怎么就攤上這事⌒诶矗” “怎么了续膳?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長收班。 經常有香客問我坟岔,道長,這世上最難降的妖魔是什么摔桦? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任社付,我火速辦了婚禮,結果婚禮上邻耕,老公的妹妹穿的比我還像新娘鸥咖。我一直安慰自己,他們只是感情好兄世,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布啼辣。 她就那樣靜靜地躺著,像睡著了一般御滩。 火紅的嫁衣襯著肌膚如雪熙兔。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天艾恼,我揣著相機與錄音,去河邊找鬼麸锉。 笑死钠绍,一個胖子當著我的面吹牛,可吹牛的內容都是我干的花沉。 我是一名探鬼主播柳爽,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼碱屁!你這毒婦竟也來了磷脯?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤娩脾,失蹤者是張志新(化名)和其女友劉穎赵誓,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡俩功,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年幻枉,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片诡蜓。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡熬甫,死狀恐怖,靈堂內的尸體忽然破棺而出蔓罚,到底是詐尸還是另有隱情椿肩,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布豺谈,位于F島的核電站郑象,受9級特大地震影響,放射性物質發(fā)生泄漏核无。R本人自食惡果不足惜扣唱,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望团南。 院中可真熱鬧噪沙,春花似錦、人聲如沸吐根。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拷橘。三九已至局义,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間冗疮,已是汗流浹背萄唇。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留术幔,地道東北人另萤。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像诅挑,于是被迫代替她去往敵國和親四敞。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內容