Jetpack架構元件庫-DataBinding真香

作者:heiyulong

授權原文:https://mp。weixin。qq。com/s/n7VuWeZnx_1Ds5guMqsYSA

前言

Data Binding是一種支援庫,藉助該庫,您可以使用宣告性格式(而非程式化地)將佈局中的介面元件繫結到應用中的資料來源。

佈局通常是使用呼叫介面框架方法的程式碼在 Activity 中定義的。例如,以下程式碼呼叫 findViewById() 來查詢 TextView 控制元件並將其繫結到 viewModel 變數的 userName 屬性:

TextView textView = findViewById(R。id。sample_text);    textView。setText(viewModel。getUserName());

以下示例展示瞭如何在佈局檔案中使用Data Binding 將文字直接分配到TextView。這樣就無需呼叫上述任何 Java 程式碼。請注意賦值表示式中 @{} 語法的使用:

注意

如果您使用Data Biding的主要目的是取代 findViewById() 呼叫,請考慮改用ViewBinding。

使用過ButterKnife的都知道,目前ButterKnife作者建議切換至ViewBindng使用;在許多情況下,ViewBinding可簡化實現,提高效能,提供與DataBinding相同的好處。

dataBinding 的優勢

雙向資料繫結

資料發生改變後,dataBinding 會自動通知 UI 重新整理頁面,不再需要人工繫結最新資料到 View 上。UI 改變後也能同步給資料。

減少模板程式碼

有了 dataBinding,從此不用再寫 findViewById,setOnClickListener 等枯燥生硬的程式碼,大大提高工作效率。從此 Butterknife 靠邊站。

釋放 Activity/Fragment

以前,我們在 Activity , Fragment 或 Presenter 中計算資料再繫結到 View 元件上,導致 View 層很臃腫,現在這部分工作我們可以直接在 xml 佈局檔案中完成。Activity , Fragment 讓它更加只關注核心業務。

資料繫結空安全

在 xml 中繫結資料它是空安全的,因為 dataBinding 在資料繫結上會自動裝箱和空判斷,所以大大減少了資料繫結帶來的 NullpointException 問題。

在使用 dataBinding 的時候,很多同學會誤以為不方便除錯;

現在的 databinding 在編譯階段也會有豐富的錯誤提示,在執行階段,我們可以根據佈局檔案找到實現類,跟進去斷點排查問題。

如fragment_layout_my。xml佈局,在編譯時會生成 FragmentLayoutMyImpl。java 實現類,我們可以搜尋這種類 debug 跟進解決問題。

Data Binding使用場景:

Data Binding使用前需要先引入

在app的build。gradle中加上以下程式碼即可,不用引用其他的依賴

android {    。。。    dataBinding {        enabled = true    }}

佈局和繫結表示式

資料繫結的佈局以根標記 layout 開頭,後跟 data 元素和 view 根元素。如下:

注意

:佈局表示式應保持精簡,因為它們無法進行單元測試,並且擁有的 IDE 支援也有限。為了簡化佈局表示式,可以使用自定義繫結介面卡。

<?xml version=“1。0” encoding=“utf-8”?>                    <!——data 中的 user 變數描述了可在此佈局中使用的屬性。    ——>                                           <!——佈局中的表示式使用“@{}”語法給控制元件賦值。——>                                 

==系統會為每個佈局檔案生成一個繫結類==。

1、預設情況下,類名稱基於佈局檔案的名稱,它會轉換為駝峰形式並在末尾新增 Binding 字尾。

2、以上佈局檔名為 activity_main。xml,因此生成的對應類為 ActivityMainBinding,==且都是ViewDataBinding的子類,所有佈局對應的生成的繫結類都可以是ViewDataBinding類==

3、此類包含從佈局屬性(例如,user 變數)到佈局檢視的所有繫結,並且知道如何為繫結表示式指定值。

4、建議的繫結建立方法是在擴充佈局時建立,如以下示例所示:

@Override    protected void onCreate(Bundle savedInstanceState) {       super。onCreate(savedInstanceState);       //此時可以透過DataBindingUtil來設定Activity的頁面佈局。       //此時會返回一個ActivityMainBinding物件。       //這個是編譯時根據xml佈局檔案中的資料繫結自動生成的實現類。       ActivityMainBinding binding = DataBindingUtil。setContentView(this, R。layout。activity_main);       User user = new User(“Test”, “User”);       //完成資料繫結       binding。setUser(user);    }

a、Activity 資料繫結 ( DataBinding ) :

1、DataBindingUtil類方法:

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

2、生成的佈局繫結類的inflate()方法:

ActivityMainBinding binding = ActivityMainBinding。inflate(getLayoutInflater());

@Override    protected void onCreate(Bundle savedInstanceState) {       super。onCreate(savedInstanceState);       //DataBindingUtil類方法       ActivityMainBinding binding = DataBindingUtil。setContentView(this, R。layout。activity_main);       //生成的佈局繫結類的inflate()方法       //ActivityMainBinding binding = ActivityMainBinding。inflate(getLayoutInflater());       User user = new User(“Test”, “User”);       binding。setUser(user);    }

b、 Fragment、ListView 或 RecyclerView 介面卡中使用資料繫結 ( DataBinding )

DataBindingUtil 或 生成的佈局繫結類deinflate() 方法,如以下程式碼示例所示:

ListItemBinding binding = ListItemBinding。inflate(layoutInflater, viewGroup, false);    // or    ListItemBinding binding = DataBindingUtil。inflate(layoutInflater, R。layout。list_item, viewGroup, false);

Data Binding繫結表示式:

xml裡支援使用以下表達式:

算術運算子 + - / * %

字串連線運算子 +

邏輯運算子 && ||

二元運算子 & | ^

一元運算子 + - ! ~

移位運算子 >> >>> <<

比較運算子 == > < >= <=(請注意,< 需要轉義為 <)

instanceof

分組運算子 ()

字面量運算子 - 字元、字串、數字、null

型別轉換

方法呼叫

欄位訪問

陣列訪問 []

三元運算子 ?:

不支援以下表達式:

this

super

new

顯式泛型呼叫

a、變數

1、生成的資料繫結程式碼會自動檢查有沒有 null 值並避免出現 Null 指標異常。

2、例如,在表示式 @{user。name} 中,如果 user 為 Null,則為 user。name 分配預設值 null。

3、如果您引用 user。age,其中 age 的型別為 int,則資料繫結使用預設值 0。

<!——變數給控制元件賦值——>android:text=“@{user。name}”<!——控制元件給變數賦值(雙向繫結)——>android:text=“@={user。name}”

b、Null 合併運算子(空運算子)

如果左邊運算數不是 null,則 Null 合併運算子 (??) 選擇左邊運算數,如果左邊運算數為 null,則選擇右邊運算數。

android:text=“@{user。displayName ?? user。lastName}”//等效於如下三目表示式android:text=“@{user。displayName != null ? user。displayName : user。lastName}”

c、檢視引用

1、表示式可以透過以下語法按 ID 引用佈局中的其他檢視:

2、繫結類將 ID 轉換為駝峰式大小寫。

3、在以下示例中,TextView 檢視引用同一佈局中的 EditText 檢視:

android:text="@{exampleText.text}"

    

d、顯示隱藏控制

1、首先在 xml 的 data 節點中引用View

2、然後設定visibility

    android:visibility=“@{student。boy ? View。VISIBLE : View。INVISIBLE}”

e、事件處理

方法引用:

==android:onClick=“@{handlers::onClickFriend}”==

繫結表示式可將檢視的點選監聽器分配給MyHandlers 類的 onClickFriend() 方法,如下所示:

public class MyHandlers {        public void onClickFriend(View view) { 。。。 }    }

<?xml version=“1。0” encoding=“utf-8”?>                                                                     

注意:

1、在表示式中,您可以引用符合監聽器方法簽名的方法。

2、當表示式求值結果為方法引用時,資料繫結會將方法引用和所有者物件封裝到監聽器中,並在目標檢視上設定該監聽器。

3、如果表示式的求值結果為 null,則資料繫結不會建立監聽器,而是設定 null 監聽器。

4、表示式中的方法簽名必須與監聽器物件中的方法簽名完全一致。

監聽器繫結:

==android:onClick=“@{() -> presenter。onSaveClick(task)}”==

繫結表示式可將檢視的點選事件繫結打給Presenter 類的 onSaveClick(Task task) 方法,如下所示:

public class Presenter {        public void onSaveClick(Task task){}    }

<?xml version=“1。0” encoding=“utf-8”?>                                                                 presenter。onSaveClick(task)}” />            

以上,我們尚未定義傳遞給 onClick(View) 的 view 引數。

監聽器繫結提供兩個監聽器引數選項:您可以忽略方法的所有引數,也可以命名所有引數。

如果您想命名引數,則可以在表示式中使用這些引數。

例如,上面的表示式可以寫成如下形式:

android:onClick=“@{(view) -> presenter。onSaveClick(task)}”

或者,如果您想在表示式中使用引數,則採用如下形式:

public class Presenter {        public void onSaveClick(View view, Task task){}    }

android:onClick=“@{(theView) -> presenter。onSaveClick(theView, task)}”

監聽長按事件,表示式應返回一個布林值。

public class Presenter {        public boolean onLongClick(View view, Task task) { }    }  android:onLongClick=“@{(theView) -> presenter。onLongClick(theView, task)}”

注意:

1、監聽器繫結這些是在事件發生時進行求值的 lambda 表示式。

2、資料繫結始終會建立一個要在檢視上設定的監聽器。

3、事件被分派後,監聽器會對 lambda 表示式進行求值。

dataBinding 可以拓展 View 屬性

以前想要給 ImageView 增加幾個屬性,必須要寫個自定義的 ImageView 在建構函式中一頓解析。

那看看使用 dataBinding 如何拓展 View 屬性。

public class CustomImageView extends ImageView{   //需要使用BindingAdapter註解並標記在public static方法上。    //value中的欄位隨意新增和方法引數一一對應即可。   @BindingAdapter(value = {“image_url”, “isCircle”})    public static void setImageUrl(PPImageView view, String imageUrl, boolean isCircle) {        view。setImageUrl(view, imageUrl, isCircle, 0);    }    //requireAll = false代表是否以下三個屬性在xml中同時使用才會呼叫到該方法    //為false的話,只要有一個屬性被使用就能呼叫到該方法    @BindingAdapter(value = {“image_url”, “isCircle”, “radius”}, requireAll = false)    public static void setImageUrl(PPImageView view, String imageUrl, boolean isCircle, int radius) {       ……      }   }//在佈局檔案中如下使用,便能實現圖片圓角和資源Url繫結的功能 

BindingAdapter

繫結介面卡,是 Jetpack DataBinding 中用來擴展布局 xml 屬性行為的註解;

允許你針對佈局 xml 中的一個或多個屬性進行繫結行為擴充套件;

這個屬性可以是自定義屬性,也可以是原生屬性。

這個擴充套件行為可以是簡單的ViewModel屬性與控制元件賦值繫結,也可以是關聯某個控制元件屬性的額外操作,

例如在設定屬性之前進行值域檢查,或型別轉換,或者統一處理一些事情。

後臺私信回覆 1024 免費領取 SpringCloud、SpringBoot,微信小程式、Java面試、資料結構、演算法等全套影片資料。