databinding學習筆記

本文是https://github.com/LyndonChin/MasteringAndroidDataBinding的學習筆記java

DataBinding簡要

準備

保證Gradle插件版本不低於1.5.0-alpha1android

修改對應模塊的build.gradle:git

dataBinding{
    enabled true
}

佈局文件

最外層根節點變爲layout,新增節點data用來存放頁面可能用的數據以及方法。github

<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
    </data>
    <!--原先的根節點(Root Element)-->
    <LinearLayout>
    ....
    </LinearLayout>
</layout>

數據對象

須要注意的是在數據對象中必須實現每一個屬性的get和set方法。api

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() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }
}

若是須要雙向綁定則須要繼承BaseObservable類,該類實現了監聽器的註冊機制(未驗證)。app

public class ObservableUser extends BaseObservable {
    private String firstName;
    private String lastName;

    @Bindable
    public String getFirstName() {
        return firstName;
    }

    @Bindable
    public String getLastName() {
        return lastName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
        notifyPropertyChanged(BR.firstName);
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
        notifyPropertyChanged(BR.lastName);
    }
}

BR 是編譯階段生成的一個類,功能與 R.java 相似,用 @Bindable 標記過 getter 方法會在 BR 中生成一個 entry框架

經過代碼能夠看出,當數據發生變化時仍是須要手動發出通知。 經過調用 notifyPropertyChanged(BR.firstName) 能夠通知系統 BR.firstName 這個 entry 的數據已經發生變化,須要更新 UI。ide

Variable和import

這兩個標籤是在layout資源文件中data標籤的下級標籤,其中variable標籤能夠獨自使用,其獨自使用方法以下:佈局

<data>
    <variable name="user" type="com.xxx.xxx.xxx.User" />
</data>

其中name對應的字段會在具體view控件賦值時用到,type字段對應值是具體引用的類的全路徑。學習

variable和import方法聯合使用方法以下:

<data>
    <import type="com.xxx.xxx.xxx.User" />
    <variable name="user" type="User" />
</data>

import使用方法與java相似,當使用了import後,variable的type標籤就可使用類名而不是全路徑了

多個路徑類名相同的解決方法

<import type="com.example.home.data.User" />
<import type="com.examle.detail.data.User" alias="DetailUser" />
<variable name="user" type="DetailUser" />

如上面代碼所示當引用了不一樣路徑的兩個 User 類時,須要給其中一個設置別名alias,這樣在給variable標籤中的type字段賦值時就能夠避免衝突。

綁定variable

當設置了variable標籤後,框架會自動生成一個繼承自ViewDataBinding的類,若是data中有class屬性,好比

<data class="com.example.CustomBinding">
</data>

則生成的類名爲CustomBinding,不然就根據layout的文件名來生成對應的Binding類,例如R.layout.activity_main對應生成的類名爲ActivityMainBinding。自動生成的類在build目錄下,as中不可見。

具體在Activity中的綁定方法以下

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ActivityBasicBinding binding = DataBindingUtil.setContentView(
            this, R.layout.activity_basic);
    User user = new User("fei", "Liang");
    binding.setUser(user);
}

用DataBindingUtil.setContentView來獲取一個ActivityBasicBinding的實例binding來實現綁定,binding經過set方法來設置variable中對應的屬性。

除了setContentView方法外,DataBindingUtil還提供了一個靜態方法bind(View v)來實現xml和對應的ViewDataBinding的綁定。該方法能夠用於adper和fragment中的xml綁定。

使用variable

數據與 Variable 綁定以後,xml 的 UI 元素就能夠直接使用了。使用方法爲:屬性="@{[variable.name].[property]}"例如:

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{user.lastName}" />

java類靜態方法的使用

首先定義一個靜態方法

public class MyStringUtils {
    public static String capitalize(final String word) {
        if (word.length() > 1) {
            return String.valueOf(word.charAt(0)).toUpperCase() + word.substring(1);
        }
        return word;
    }
}

而後在 xml 的 data 節點中導入:

<import type="com.liangfeizc.databindingsamples.utils.MyStringUtils" />

使用方法與 Java 語法同樣:

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{MyStringUtils.capitalize(user.firstName)}" />

BindingAdapter

public class TestUtils{
    @BindingAdapter("bind:imageUrl")
    public static void imageLoader(ImageView view,String url){
        ImageLoader.getInstance().display(url,view)
    }
}
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <data >
        <import type="com.vip.vf.android.home.api.model.ActiveModel"></import>
        <import type="com.vip.vf.android.common.uitils.TestUtils"></import>
        <variable
            name="model"
            type="ActiveModel"/>
        <variable
            name="isBottom"
            type="boolean"/>
        <variable
            name="utils"
            type="TestUtils"/>
        <variable
            name="imageUrl"
            type="String"/>
    </data>
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:background="@color/vfWhiteColor">
        <ImageView
            android:id="@+id/image"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="fitXY"
            app:imageUrl = "@{imageUrl}"
            />
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </RelativeLayout>
</layout>

以上代碼實現的功能是經過設置xml中的imageUrl屬性來調用java文件中TestUtils的方法imageLoader,具體須要加載圖片的時候只要調用相應的binding class的setimageUrl方法便可完成,能夠有效的避免在Activity代碼中屢次引用ImageLoader這個方法。

自定義view的屬性

自定義view能夠直接經過set方法來連接xml的相應屬性。

<com.xxx.xxx.xxx.UserView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingLeft="@dimen/largePadding"
    app:onClickListener="@{activity.clickListener}"
    app:firstName="@{@string/firstName}"
    app:lastName="@{@string/lastName}"
    app:age="27" />

在如上xml佈局文件中,有兩個屬性firstName和lastName,只要在Java文件UserView中實現兩個set方法,不須要專門寫style屬性。

public void setFirstName(@NonNull final String firstName){
    mFirstName.setText(firstName);
}
public void setLastName(@NonNull final String lastName) {
    mLastName.setText(lastName);
}

帶 ID 的 View

Data Binding 有效下降了代碼的冗餘性,甚至徹底沒有必要再去獲取一個 View 實例,可是狀況不是絕對的,萬一咱們真的就須要了呢?不用擔憂,只要給 View 定義一個 ID,Data Binding 就會爲咱們生成一個對應的 final 變量。

<TextView
    android:id="@+id/firstName"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

上面代碼中定義了一個 ID 爲 *firstName** 的 TextView,那麼它對應的變量就是

public final TextView firstName;

使用時咱們直接調用相應的binding.firstName就能夠對應到相應的TextView

Null Coalescing 運算符

android:text="@{user.displayName ?? user.lastName}"

就等價於

android:text="@{user.displayName != null ? user.displayName : user.lastName}"

屬性值

經過 @{} 能夠直接把 Java 中定義的屬性值賦值給 xml 屬性。

<TextView
   android:text="@{user.lastName}"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"/>

使用資源數據

<TextView
    android:padding="@{large? (int)@dimen/largePadding : (int)@dimen/smallPadding}"
    android:background="@android:color/black"
    android:textColor="@android:color/white"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/hello_world" />
相關文章
相關標籤/搜索