DataBinding系列(四):DataBinding進階之路
透過前面的學習,我們已經會使用DataBinding的一些基礎語法了,而這一篇,我就和大家一起開啟DataBinding的進階之旅,下面就讓我們透過幾個小例子一起起飛吧。
1.BindingAdapter註解設定自定義屬性
BindingAdapter對於自定義屬性是非常有用的,舉個例子,如果你的專案中用到了Glide,或者是其他的圖片載入框架,由於這些框架一般透過url給ImageView設定圖片的,但是ImageView中並沒有設定url的屬性,這個時候,BindingAdapter就派上用場了。一起來看看是如何實現的:
public class ImageHelper { /** * 1.載入圖片,無需手動呼叫此方法 * 2.使用@BindingAdapter註解設定自定義屬性的名稱,imageUrl就是屬性的名稱, * 當ImageView中使用imageUrl屬性時,會自動呼叫loadImage方法, * * @param imageView ImageView * @param url 圖片地址 */ @BindingAdapter({"imageUrl"}) public static void loadImage(ImageView imageView, String url) { Glide.with(imageView.getContext()).load(url) .placeholder(R.mipmap.fruit) .error(R.mipmap.fruit) .into(imageView); } }
使用@BindingAdapter註解設定自定義屬性的名稱,如上所示,imageUrl就是屬性的名稱,當ImageView中使用imageUrl屬性時,會自動呼叫loadImage方法,引數imageView為當前使用imageUrl屬性的ImageView,引數url為圖片地址。
xml中使用自定義屬性
<!-- 當imageUrl屬性存在時,會自動呼叫ImageHelper的loadImage方法 -->
Activity中設定圖片的url
public class BasicActivity extends AppCompatActivity { //使用者頭像 private static final String URL_USER_PIC = ""; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityBasicBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_basic); UserBean userBean = new UserBean(URL_USER_PIC, "張三", 24); binding.setUser(userBean); } }
這樣就可以在DataBinding中使用Glide來載入圖片了,此外,BindingAdapter也是允許設定多個屬性的,如下:
@BindingAdapter({"imageUrl", "placeHolder",error"}) public static void loadImage(ImageView view, String url, Drawable holderDrawable, Drawable errorDrawable) { Glide.with(imageView.getContext()) .load(url) .placeholder(holderDrawable) .error(errorDrawable) .into(imageView); }
2.資料物件 (Data Objects)
任何plain old Java object (POJO)物件都能用在 Data Binding 中,但是有個問題,當我們的資料來源發生改變的時候,UI介面上顯示的還是之前的資料,並沒有同步更新,這顯然是不行的。不知道大家還記不記得,RecyclerView或者ListView是如何更新資料的?資料是透過Adapter提供的,當資料發生改變時,我們透過notifyDatasetChanged透過UI去改變資料,這是透過一個觀察者模式來實現的,很幸運,查閱原始碼後發現DataBinding也是透過觀察者模式來實現的。
DataBinding動態更新資料的2種方式
BaseObservable
ObservableFields
BaseObservable
我們可以透過Observable的方式去通知UI重新整理資料,Observable 是一個包含新增/移除 listener 的機制的介面,為了簡化開發,Android 原生提供了一個基類 BaseObservable 來實現 listener 序號產生器制。這個類也實現了欄位變動的通知,只需要在 getter 上使用 Bindable 註解,並在 setter 中通知更新即可。
定義一個實體類,並繼承BaseObservable
public class DoubleBindBean extends BaseObservable { //BR 是編譯階段生成的一個類,功能與 R.java 類似,用 @Bindable 標記過 getter 方法會在 BR 中生成一個 entry,當我們 //透過程式碼可以看出,當資料發生變化時還是需要手動發出通知。 透過呼叫notifyPropertyChanged(BR.firstName)來通知系統 BR.firstName 這個 entry 的資料已經發生變化,需要更新 UI。 private String content; //內容 public DoubleBindBean(String content) { this.content = content; } @Bindable public String getContent() { return content; } public void setContent(String content) { this.content = content; notifyPropertyChanged(BR.content); //通知系統資料來源發生變化,重新整理UI介面 } }
BR 是編譯階段生成的一個類,功能與 R.java 類似,用 @Bindable 標記過 getxxx() 方法會在 BR 中生成一個 entry。 當資料發生變化時需要呼叫 notifyPropertyChanged(BR.content) 通知系統 BR.content這個 entry 的資料已經發生變化以更新UI。
xml:
Activity:
public class DoubleBindActivity extends AppCompatActivity implements View.OnClickListener { private DoubleBindBean doubleBindBean; private boolean flag; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityDoubleBindBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_double_bind); doubleBindBean = new DoubleBindBean("我是原始內容"); binding.setDoubleBindBean(doubleBindBean); binding.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.change_content_btn: //BaseObservable flag = !flag; if (flag) { doubleBindBean.setContent("我是更新後的內容"); } else { doubleBindBean.setContent("我是原始內容"); } break; } }
ObservableFields
如果想要省時,或者資料類的欄位很少的話,可以使用 ObservableField 以及它的派生 ObservableBoolean、 ObservableByte ObservableChar、ObservableShort、ObservableInt、ObservableLong、ObservableFloat、ObservableDouble、 ObservableParcelable 等。
它的實現就更簡潔了,如下
public class DoubleBindBean2 { //變數需要為public public final ObservableFieldusername = new ObservableField(); }
Activity:
public class DoubleBindActivity extends AppCompatActivity implements View.OnClickListener { private DoubleBindBean2 doubleBindBean2; private boolean flag2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityDoubleBindBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_double_bind); doubleBindBean2 = new DoubleBindBean2(); doubleBindBean2.username.set("我是原始內容2"); binding.setDoubleBindBean2(doubleBindBean2); binding.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.change_content_btn2: //ObservableFields flag2 = !flag2; if (flag2) { doubleBindBean2.username.set("我是更新後的內容2"); } else { doubleBindBean2.username.set("我是原始內容2"); } break; } } }
Observable Collections
除了支援ObservableField,ObservableBoolean,ObservableInt等基礎變數型別以外,當然也支援集合框架拉,比如:ObservableArrayMap,ObservableArrayList。使用和普通的Map、List基本相同
" /> " />
Activity:
public class DoubleBindActivity extends AppCompatActivity implements View.OnClickListener { private ObservableArrayListlist=new ObservableArrayList(); private ObservableArrayMap map = new ObservableArrayMap(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityDoubleBindBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_double_bind); list.add("list1"); list.add("list2"); binding.setList(list); map.put("key0","key0_value0"); map.put("key1","key1_value1"); binding.setMap(map); binding.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.change_content_btn3: list.set(0,"after change list"); break; case R.id.change_content_btn4: map.put("key0","after change key0_value0"); break; } } }
View with ID
如果我們需要在Activity中獲取某個View來進行一些操作,那該怎麼辦呢?別擔心,有辦法,佈局中每一個帶有 ID 的 View,都會生成一個 public final 欄位。binding 過程會做一個簡單的賦值,在 binding 類中儲存對應 ID 的 View。這種機制相比呼叫 findViewById 效率更高。舉個例子:
Activity
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main); binding.userName.setText("content") } }
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2894/viewspace-2813525/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Android DataBinding 從入門到進階Android
- Android DataBinding 從入門到進階(2)Android
- MultiItem進階 使用DataBinding 讓 RecyclerView程式碼更簡潔清爽View
- React 進階之路(四)React
- MVVM 中的DatabindingMVVM
- Android Jetpack - DataBindingAndroidJetpack
- DataBinding實用指南
- MVVM模式--DataBinding的使用MVVM模式
- DataBinding基礎使用一
- DataBinding基礎使用二
- DataBinding基礎使用三
- databinding的點選事件事件
- MVVM dataBinding 學習心得MVVM
- Android DataBinding之初體驗Android
- MVVM架構篇之DataBinding(-)MVVM架構
- Android:DataBinding的一二事Android
- DataBinding中xml 點選事件XML事件
- databinding字串拼接不支援中文字串
- Databinding與LiveData的合作LiveData
- Databinding 雙向繫結詳解
- 高仿掘金App —— 基於 databindingAPP
- DataBinding資料繫結基本講解
- 雞你太美之 Kotlin 和 DatabindingKotlin
- Android Jetpack(2):DataBinding的基本使用AndroidJetpack
- DataBinding點選事件沒有反應事件
- Android架構元件-DataBinding的使用Android架構元件
- DataBinding繫結android:onClick出錯Android
- .NET進階系列之四:深入DataTable
- Python 從入門到進階之路(四)Python
- Android開發:Kotlin下配置DataBindingAndroidKotlin
- Android 架構選型 (MVP+DataBinding)Android架構MVP
- Android資料繫結框架DataBinding用法Android框架
- koa2 從入門到進階之路 (四)
- JetPack 學習筆記:Databinding 與響應式Jetpack筆記
- Android Studio: Kotlin使用DataBinding異常AndroidKotlin
- Typescript進階之路TypeScript
- Java進階之路Java
- 打造基於Databinding與RecyclerView的通用Adapter類ViewAPT