首頁>技術>

授權原文: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 程式碼。請注意賦值表示式中 @{} 語法的使用:

<TextView        android:text="@{viewmodel.userName}" />

注意

如果您使用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 支援也有限。為了簡化佈局表示式,可以使用自定義繫結介面卡。

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型別轉換方法呼叫欄位訪問陣列訪問 []三元運算子 ?:

不支援以下表達式:

thissupernew顯式泛型呼叫

a、變數

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

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

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

如果左邊運算數不是 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}"

<EditText    android:id="@+id/example_text"    android:layout_height="wrap_content"    android:layout_width="match_parent"/>    <TextView    android:id="@+id/example_output"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:text="@{exampleText.text}"/>

d、顯示隱藏控制

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

2、然後設定visibility

<data>    <import type="android.view.View"/></data>android:visibility="@{student.boy ? View.VISIBLE : View.INVISIBLE}"

e、事件處理

方法引用:

==android:onClick="@{handlers::onClickFriend}"==

    public class MyHandlers {        public void onClickFriend(View view) { ... }    }
<?xml version="1.0" encoding="utf-8"?>    <layout xmlns:android="http://schemas.android.com/apk/res/android">       <data>           <variable name="handlers" type="com.example.MyHandlers"/>           <variable name="user" type="com.example.User"/>       </data>       <LinearLayout           android:orientation="vertical"           android:layout_width="match_parent"           android:layout_height="match_parent">           <TextView android:layout_width="wrap_content"               android:layout_height="wrap_content"               android:text="@{user.firstName}"               android:onClick="@{handlers::onClickFriend}"/>       </LinearLayout>    </layout>

注意:

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

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

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

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

監聽器繫結:

==android:onClick="@{() -> presenter.onSaveClick(task)}"==

    public class Presenter {        public void onSaveClick(Task task){}    }
<?xml version="1.0" encoding="utf-8"?>    <layout xmlns:android="http://schemas.android.com/apk/res/android">        <data>            <variable name="task" type="com.android.example.Task" />            <variable name="presenter" type="com.android.example.Presenter" />        </data>        <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent">            <Button android:layout_width="wrap_content" android:layout_height="wrap_content"            android:onClick="@{() -> presenter.onSaveClick(task)}" />        </LinearLayout>    </layout>

以上,我們尚未定義傳遞給 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繫結的功能 <CustomImageView            .......            app:image_url ="@{user.avatar}"            app:radius="@{50}"></CustomImageView>

BindingAdapter

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

允許你針對佈局 xml 中的一個或多個屬性進行繫結行為擴充套件;這個屬性可以是自定義屬性,也可以是原生屬性。這個擴充套件行為可以是簡單的ViewModel屬性與控制元件賦值繫結,也可以是關聯某個控制元件屬性的額外操作,例如在設定屬性之前進行值域檢查,或型別轉換,或者統一處理一些事情。

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

22
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 技術分享 | 大量 Opening tables 案例分析