標籤雲

搜尋此網誌

2015/11/24

Data Binding-1

Android 從 Marshmallow 開始新增了 Data Binding Library
由於它是一個 support library
所以最低可以支援到 Android 2.1 (API level 7)

要使用 Data Binding 的話需要一些條件:
1. Android Studio 1.3 以上
2. Android Plugin for Gradle 1.5.0-alpha1 以上
3. 在 app 的 build.gradle 加入 dataBinding 設定
android {
    ....
    dataBinding {
        enabled true
    }
}

Data Binding 的 layout xml 檔範例如下:
<?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"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context="com.fuhu.testdatabinding.MainActivity"
    >
    <data>
        <variable
            name="dataObj"
            type="com.fuhu.testdatabinding.MyDataObj"
            />
        <variable
            name="handlers"
            type="com.fuhu.testdatabinding.MyHandlers"
            />
    </data>

    <android.support.design.widget.CoordinatorLayout

        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        >

        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/AppTheme.AppBarOverlay">

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="?attr/colorPrimary"
                app:popupTheme="@style/AppTheme.PopupOverlay"/>

        </android.support.design.widget.AppBarLayout>

        <include layout="@layout/content_main"
            app:customData="@{dataObj}"
            app:handlers="@{handlers}"
            />

        <android.support.design.widget.FloatingActionButton
            android:id="@+id/fab"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom|end"
            android:layout_margin="@dimen/fab_margin"
            android:src="@android:drawable/ic_dialog_email"/>

    </android.support.design.widget.CoordinatorLayout>
</layout>

首先,root element 是 layout tag
binding 的 data object 則是在 data tag 中的 variable
而使用物件的值則是用 @{varname.attribute} 的寫法

另外由於我們使用了 include 的方式
所以用 app 自訂屬性把 dataObj 變數以 customData 的自訂屬性名稱傳進去

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.fuhu.testdatabinding.MainActivity"
    tools:showIn="@layout/activity_main"
    >
    <data>
        <variable
            name="customData"
            type="com.fuhu.testdatabinding.MyDataObj"
            />
        <variable
            name="handlers"
            type="com.fuhu.testdatabinding.MyHandlers"
           />
    </data>
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        >
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{customData.alias}"
            android:onClick="@{customData.isMember ? handlers.onClickMemberData : handlers.onClickLogin}"
            />
    </RelativeLayout>
</layout>

而被 include 的 xml 檔案也要使用 layout tag 作為 root element
並定義 customData 變數與型別
就可以在檔案內使用該變數實體的屬性

Data Object 可以用 plain-old Java object (POJO) 或是 JavaBeans object
JavaBeans object 範例如下:
public class MyDataObj {

    public boolean isMember = false;

    private String alias;
    public String getAlias() { return alias; }
    public void setAlias(String alias) {
        this.alias = alias;
    }

    private String imageUrl;
    public String getImageUrl() { return imageUrl; }
    public void setImageUrl(String imageUrl) {
        this.imageUrl = imageUrl;
    }
}

而 data 的 Binding 則是透過以下的寫法:
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
//    setContentView(R.layout.activity_main);
    ActivityMainBinding testbinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
    MyDataObj dataObj = new MyDataObj();
    dataObj.setAlias("Oh yeah !! It works.");
    testbinding.setDataObj(dataObj);
    MyHandlers handlers = new MyHandlers();
    testbinding.setHandlers(handlers);
    ...(省略)
}

可以看到我們把原本的 setContentView 改成了 DataBindingUtil.setContentView(this, R.layout.activity_main)
並把 MyDataObj 實體利用 setXXXXX 方法設定給 view

ActivityMainBinding 是自動生成的
layout 名稱為 activity_main 所以自動生成的 Binding 類別就叫做 ActivityMainBinding
相對的如果 layout 是 item_check_list 那 Binding 類別就叫做 ItemCheckListBinding

而除了 DataBindingUtil.setContentView 外
也可以使用
MainActivityBinding binding = MainActivityBinding.inflate(getLayoutInflater());

如果是使用 ListView 或 RecyclerView adapter 可以用:
ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, false);

ListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false);

再來討論一下 event 的 binding
我們需要用原本的事件屬性將事件指到我們自己的 handler
如上面的 android:onClick="@{dataObj.isMember ? handlers.onClickMemberData : handlers.onClickLogin}"

public class MyHandlers {
    public void onClickMemberData(View view) {
        ...(省略)
    }
    public void onClickLogin(View view) {
        ...(省略)
    }
}

相關資料:
YouTube - Android Marshmallow 6.0: Data Binding Library
Data Binding Guide

沒有留言: