1. 程式人生 > >DataBinding快速入門

DataBinding快速入門

一、DataBinding介紹

DataBinding翻譯過來就是資料繫結,把資料繫結在控制元件上。本篇講述的都是單向繫結,即資料繫結到控制元件上。現在已經支援雙向繫結,也就是說,還可以把控制元件繫結在資料上。

DataBinding可以代替findViewById,讓程式碼更簡潔,而且比註解框架(如ButterKnife)效率高。

二、DataBinding使用

2.1 準備工作

環境要求:

Gradle 外掛版本不低於 1.5.0-alpha1
Android Studio 版本要高於 1.3
在module(如:app)的build.gradle中新增dataBinding的使能開關

android {
    compileSdkVersion 24
    buildToolsVersion "23.0.2"

    defaultConfig {
      
    }

    // add
    dataBinding{
        enabled true
    }


然後使用Sync now同步。

2.2 快速使用

2.2.1 建立一個Bean類


建立一個User類:

public class User{
    String name;
    String nickname;
    boolean isMale;
    int age;

    public User(String name, String nickname, boolean isMale, int age) {
        this.name = name;
        this.nickname = nickname;
        this.isMale = isMale;
        this.age = age;
    }
   //Getter and Setter,省略
}


2.2.2 修改xml佈局檔案

步驟:

1.在原佈局檔案外套一層layout標籤,把名稱空間移到layout標籤內
2.layout標籤內部包含資料模組和樣式模組(原佈局)
3.資料模組使用data標籤,定義變數名稱name——下面android:text屬性中呼叫的名稱,及型別type——定義變數所指的型別或類(如果是自定義類,必須給完整包名+類名)

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <variable
            name="user"
            type="com.zjun.databinding.demo.bean.User" />
    </data>

    <LinearLayout
        android:id="@+id/activity_fast_use"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="@dimen/activity_vertical_margin"
        tools:context="com.zjun.databinding.demo.FastUseActivity">

        <LinearLayout style="@style/StyleItemParent">

            <Button
                android:id="@+id/btn_load"
                style="@style/StyleBeforeText"
                android:text="資料1" />

            <Button
                android:id="@+id/btn_change"
                style="@style/StyleBeforeText"
                android:text="資料2" />
        </LinearLayout>

        <LinearLayout style="@style/StyleItemParent">

            <TextView
                style="@style/StyleBeforeText"
                android:text="姓名:" />

            <TextView
                style="@style/StyleAfterText"
                android:text="@{user.name}"
                android:onClick="@{user.onNameClick}"/>
        </LinearLayout>

        <LinearLayout style="@style/StyleItemParent">

            <TextView
                style="@style/StyleBeforeText"
                android:text="暱稱:" />

            <TextView
                style="@style/StyleAfterText"
                android:text="@{user.nickname ?? user.name}"
                android:onLongClick="@{user.onNicknameLongClick}"/>
        </LinearLayout>

        <LinearLayout style="@style/StyleItemParent">

            <TextView
                style="@style/StyleBeforeText"
                android:text="性別:" />

            <TextView
                style="@style/StyleAfterText"
                android:textColor="@{user.male ? 0xFF0000FF : 0xFFFF0000}"
                android:text='@{user.male ? @string/male : @string/female}' />
        </LinearLayout>

        <LinearLayout style="@style/StyleItemParent">

            <TextView
                style="@style/StyleBeforeText"
                android:text="年齡:" />

            <TextView
                style="@style/StyleAfterText"
                android:textColor="@{user.age &lt; 14  || user.age &gt; 65 ? 0xFFFF0000 : 0xFF000000}"
                android:text='@{String.valueOf(user.age) + " years old"}' />
        </LinearLayout>
    </LinearLayout>
</layout>


2.2.3 xml中的使用語法

上面的資料繫結中,主要是把資料顯示android:text屬性中(點選事件暫不考慮),必須注意語法:

1.每一個變數variable都是由名稱name和型別type組成。name可以在佈局檔案中使用,也可以通過Setter和Getter在程式碼中使用。type可以是基本資料型別、集合、介面卡、自定義類等,除了基本型別,其他都必須把包名寫全


2.雙引號中可以套“`”(Tab鍵上面,非單引號),單引號內可以套雙引號;


3.不能直接用boolean和int型別的值。而且int值將被當做資原始檔。因此要使用其數值,必須轉換成字串,如(boolean同理): 
"@{user.age + ``}",或 "@{String.valueOf(user.age)}"


4.顏色必須使用ARGB制,指定其所有的透明度和單色值,以前的#F00和#FF0000無效,且前面不能加“#”


5."@{user.nickname ?? user.name}",代表user.nickname為null時顯示user.name,否則顯示自己。等同於"@{user.nickname == null ? user.name : user.nickname}"


6.比較運算子,必須使用轉義字元: 
大於號“>”——&gt; 
小於號“<”——&lt;


7.不能直接使用中文(MD),如: 
android:text='@{user.male ? "男" : "女"}' 
將報錯,得用string引用,改成: 
android:text='@{user.male ? @string/male : @string/female}'


2.2.4 程式碼中修改資料

public class FastUseActivity extends AppCompatActivity {
    private ActivityFastUseBinding mBinding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // 換掉setContentView()
    //        setContentView(R.layout.activity_fast_use);
        mBinding= DataBindingUtil.setContentView(this, R.layout.activity_fast_use);
    }

    public void onClick(View view) {
        User user = new User("張君寶", "張三丰", true, 30);
        mBinding.setUser(user);
    }
}


其中:

ActivityFastUseBinding是由佈局檔案activity_fast_use.xml的檔名生成的。


DataBindingUtil.setContextView()生成的是抽象類ViewDataBinding,但不能用作定義mBinding,因為設定資料時,需要用到其實現類的方法,如setUser()。


執行結果: 


2.3 監聽事件

可以設定控制元件的點選與長按事件。 

A. 先定義監聽事件處理方法 
在Bean類中新增點選事件:

public class User{
    String name;
    String nickname;
    boolean isMale;
    int age;

    public void onNameClick(View view) {
        Toast.makeText(view.getContext(), name + " is Clicked", Toast.LENGTH_SHORT).show();
    }

    public boolean onNicknameLongClick(View view) {
        Toast.makeText(view.getContext(), nickname + " is long Clicked", Toast.LENGTH_SHORT).show();
        return true;
    }


B. 在xml中使用


<TextView
   
    android:text="@{user.name}"
    android:onClick="@{user.onNameClick}"
/>

<TextView
   
    android:text="@{user.nickname ?? user.name}"
    android:onLongClick="@{user.onNicknameLongClick}"
/>


注意:

1.自定義監聽事件方法的引數、返回值必須與原監聽事件裡的方法一樣。如點選事件必須與onClick(View view)一樣,引數是View,返回值是void;長按事件與onLongCLick(View view)一樣,引數是View,返回值是boolean
2.android:onLongClick會提示沒有此屬性,但只要不報錯就沒關係


2.4 include的引數傳遞


佈局檔案中,經常會用到include子佈局,那如何把父佈局中的資料傳遞給子佈局呢?方法就是通過自定義屬性。 
(1)子佈局layout_include_params.xml——與之前一樣,定義資料模組,然後使用就OK:

 

<?xml version="1.0" encoding="utf-8"?>
<layout ...
    xmlns:tools="http://schemas.android.com/tools">

    <data>

        <variable
            name="user"
            type="com.zjun.databinding.demo.bean.User" />
    </data>

    <LinearLayout
        ...>

        <LinearLayout style="@style/StyleItemParent">

            <TextView
                ...
                android:text="姓名:" />

            <TextView
                ...
                android:text="@{user.name}" />
        </LinearLayout>


        <LinearLayout ...>

            <TextView
                ...
                android:text="年齡:" />

            <TextView
                ...
                android:text="@{String.valueOf(user.age) + ` years old`}" />
        </LinearLayout>
    </LinearLayout>
</layout>


(2)父佈局activity_include_params_post.xml(新增名稱空間app,用於自定義屬性,然後在include標籤中傳遞資料app:user="@{user}"):

<?xml version="1.0" encoding="utf-8"?>
<!--為了傳遞資料給子佈局,需要新增自定義屬性,先新增名稱空間app-->
<layout ...
    xmlns:app="http://schemas.android.com/apk/res-auto" >

    <data>

        <variable
            name="user"
            type="com.zjun.databinding.demo.bean.User" />
    </data>

    <RelativeLayout
        ...>

        <!--通過app:user來傳遞資料-->
        <include
            layout="@layout/layout_include_params"
            app:user="@{user}" />
    </RelativeLayout>
</layout>


2.5 List集合顯示


這裡的List的顯示,表示把List集合中的物件單獨拎出來顯示,非介面卡Adapter。如把兩個User放入List中,然後在父佈局中把物件取出來,再傳遞給子佈局。

(1)父佈局activity_list_show.xml:

<?xml version="1.0" encoding="utf-8"?>
<layout ...
    xmlns:app="http://schemas.android.com/apk/res-auto" >

    <data>
        <!--import匯入User類,與java程式碼的作用一樣。這樣下面可以直接引用,否則要寫完整的包名+類名。如果匯入了兩個類名一樣的類,可以使用別名alias來區分,變數中type寫別名-->
        <import type="com.zjun.databinding.demo.bean.User" />

        <variable
            name="userList"
            type="java.util.List&lt;User&gt;" />
    </data>

    <LinearLayout
        ... >

        <!--與運算元組一樣,用中括號獲取List中的物件-->
        <include
            layout="@layout/layout_include_list"
            ...
            app:user="@{userList[0]}" />

        <include
            layout="@layout/layout_include_list"
            ...
            app:user="@{userList[1]}" />

    </LinearLayout>
</layout>


(2)子佈局layout_include_list.xml:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <variable
            name="user"
            type="com.zjun.databinding.demo.bean.User" />

    </data>

    <TextView
        ...
        android:text="@{user.name + `[` + user.nickname + `, ` + (user.male ? `男` : `女`) + `, ` + user.age +`]`}" />
</layout>


(3)程式碼中設定資料:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ActivityListShowBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_list_show);
    List<User> userList = new ArrayList<>();
    userList.add(new User("黃藥師", "東邪", true, 30));
    userList.add(new User("歐陽鋒", "西毒", true, 33));
    binding.setUserList(userList);
}



結果: 


注意:

1.在type中的泛型同樣不能使用”<”與”>”,必須使用轉義字元"&lt;"和"&gt;"


2.轉義字元在type中會包紅色錯誤,可忽略,編譯時能通過


3.不能直接使用android:text="@{userList[0]}",即使你想列印物件的地址,也不行。這樣使用的後果是:每個databing都報“程式包不存在”的錯誤,連之前正常的也錯了。到時候你會很懵逼的


4.子佈局中的(user.male ? `男` : `女`),必須用小括號括起來


5.android:text中的資料組合很長,但也只能寫一行,目前還不知如何分行


2.6 自定義屬性——ImageView顯示圖片


2.6.1 使用註解,在程式碼中實現自定義屬性的新增


這裡專門使用了一個類DBUtils,來封裝Databinding的註解

public class DBUtils {
    /**
     * 使用DataBinding來載入圖片
     * 使用@BindingAdapter註解,註解值(這裡的imageUrl)可任取,註解值將成為自定義屬性
     * 此自定義屬性可在xml佈局檔案中使用,自定義屬性的值就是這裡定義String型別url
     * 《說明》:
     * 1. 方法名可與註解名一樣,也可不一樣
     * 2. 第一個引數必須是View,就是自定義屬性所在的View
     * 3. 第二個引數就是自定義屬性的值,與註解值對應。這是陣列,可多個
     * 這裡需要INTERNET許可權,別忘了
     *
     * @param imageView     ImageView控制元件
     * @param url           圖片網路地址
     */
    @BindingAdapter({"imageUrl"})
    public static void loadImage(ImageView imageView, String url) {
        if (url == null) {
            imageView.setImageResource(R.mipmap.ic_launcher);
        } else {
            Glide.with(imageView.getContext()).load(url).into(imageView);
        }
    }
}


2.6.2 在xml佈局檔案中使用自定義屬性


先把名稱空間寫上:xmlns:app="http://schemas.android.com/apk/res-auto" 
再使用自定義屬性imageUrl

<?xml version="1.0" encoding="utf-8"?>
<layout ...
    xmlns:app="http://schemas.android.com/apk/res-auto" >

    <data>

        <variable
            name="imgUrl1"
            type="String" />

        <variable
            name="imgUrl2"
            type="String" />

    </data>

    <RelativeLayout
        ...>

        <!--使用自定義屬性imageUrl-->
        <ImageView
            ...
            app:imageUrl="@{imgUrl1}" />

        <ImageView
            ...
            app:imageUrl="@{imgUrl2}" />

    </RelativeLayout>
</layout>


2.6.3 程式碼中設定自定義屬性值

// 獲取Activity***Binding就省略了
binding.setImgUrl1("http://avatar.csdn.net/4/9/8/1_a10615.jpg");
binding.setImgUrl2(null);


執行結果: 


2.6 ListView


ListView的展示全靠BaseAdapter,在DataBinding中也不例外。這個相對來複雜點,先把步驟寫下:

1.建立BaseAdapter的子類,因為此類可通用,所以稱CommonAdapter。內部實現核心程式碼
2.在主佈局檔案中定義變數,type型別可為BaseAdapter,也可為CommonAdapter。並把變數設定給自定義屬性adapter
3.子佈局中通過Bean來設定變數
4.在程式碼中建立CommonAdapter例項,並設定給DataBinding變數

2.6.1 建立通用的介面卡CommonAdapter

public class CommonAdapter extends BaseAdapter {
    private Context mContext;
    private List<User> mDataList;
    private int layoutId; // 條目佈局ID
    private int variableId; // DataBinding的變數ID,可通過類似R檔案的BR檔案來獲取

    public CommonAdapter(Context context, List<User> dataList, int layoutId, int variableId) {
        this.mContext = context;
        this.mDataList = dataList;
        this.layoutId = layoutId;
        this.variableId = variableId;
    }

    @Override
    public int getCount() { return mDataList.size(); }

    @Override
    public Object getItem(int position) { return mDataList.get(position); }

    @Override
    public long getItemId(int position) { return position; }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // 沒有ViewHolder的複用,但Databinding內部已經實現了複用
        ViewDataBinding binding;
        if (convertView == null) {
            binding = DataBindingUtil.inflate(LayoutInflater.from(mContext), layoutId, parent, false);
        } else {
            binding = DataBindingUtil.getBinding(convertView);
        }
        binding.setVariable(variableId, mDataList.get(position));
        return binding.getRoot();
    }
}


2.6.2 主佈局檔案中設定介面卡

<?xml version="1.0" encoding="utf-8"?>
<layout ...
    xmlns:app="http://schemas.android.com/apk/res-auto"
    >

    <data >
        <variable
            name="lvAdapter"
            type="com.zjun.databinding.demo.adapter.CommonAdapter" />
            <!--或:type="android.widget.BaseAdapter" />-->
    </data>

    <RelativeLayout
        ...>

        <!--使用自定義屬性adapter,因為有setAdapter()方法,所以無需定義-->
        <ListView
            ...
            app:adapter="@{lvAdapter}"
            />
    </RelativeLayout>
</layout>


2.6.3 條目佈局中設定資料
這個簡單,上面都已經講過了的

<?xml version="1.0" encoding="utf-8"?>
<layout ...
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>
        <variable
            name="user"
            type="com.zjun.databinding.demo.bean.User" />
    </data>

    <LinearLayout
        ...>

        <ImageView
            ...
            app:imageUrl="@{user.icon}" />

        <TextView
            ...
            android:text="@{user.name}" />
    </LinearLayout>
</layout>


2.6.4 給ListView設定Adapter

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityListViewBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_list_view);

        List<User> list = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            // 3個網路圖片1個本地圖片,依次迴圈
            User user = new User("user" + i, (i & 0x03) < 3 ? "http://avatar.csdn.net/4/9/8/1_a10615.jpg" : null);
            list.add(user);
        }

        // 建立Adapter。BR類似與R檔案,用於儲存變數名稱。位置也與R一樣,在app包名下
        CommonAdapter adapter = new CommonAdapter(this, list, R.layout.item_list_view, BR.user);
        binding.setLvAdapter(adapter);
    }


結果: 

 


2.7 ListView的條目更新


在普通的ListView中,更新資料後要立馬展示到介面上,需要notifyDataSetChanged()。在但這裡,Databinding裡使用的是觀察者模式。

實現步驟:

1.在Bean類中繼承觀察者BaseObservable
2.在需要被觀察的屬性getter方法上添加註解@Bindable。因為xml中就是通過getter來獲取值的,這裡也是為了在BR檔案生成此欄位標識
3.在更新的方法中,新增屬性更新通知方法:notifyPropertyChanged(int variableId);。一般把它放在Setter方法中,因為屬性值都是通過這裡改變的。


程式碼 


Bean類:

// 1、繼承BaseObservable
public class Member extends BaseObservable{
    private String name;
    private String icon;

    public Member(String name, String icon) {
        this.name = name;
        this.icon = icon;
    }

    // 2、在屬性值的Getter上新增@Bindable註解
    @Bindable
    public String getName() {
        return name;
    }

    // 3、在更新的地方新增屬性更新通知方法:notifyPropertyChanged(filedId);
    public void setName(String name) {
        this.name = name;
        notifyPropertyChanged(com.zjun.databinding.demo.BR.name);
    }

    public String getIcon() {
        return icon;
    }

    public void setIcon(String icon) {
        this.icon = icon;
    }

    public void onItemClick(View view) {
        setName(name + "【已更新】");
    }
}


佈局檔案(在整個條目上設定點選事件,也可以設定在某個控制元件上):

<?xml version="1.0" encoding="utf-8"?>
<layout ...
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>
        <variable
            name="member"
            type="com.zjun.databinding.demo.bean.Member" />

    </data>

    <!--設定點選事件-->
    <LinearLayout
        ...
        android:onClick="@{member.onItemClick}">

        <ImageView
            ...
            app:imageUrl="@{member.icon}" />

        <TextView
            ...
            android:text="@{member.name}" />
    </LinearLayout>
</layout>


Activity中的程式碼同上,不過我把CommonAdapter的User改成了泛型,以便通用。 
結果: 

2.8 新增自定義屬性用非static方法


前面我們載入圖片的時候,使用了註解@BindingAdapter({"imageUrl"}),和static靜態方法來新增自定義屬性。但static沒有非static功能多,有時就要用到物件等,怎麼辦?

DataBinding裡也可以通過component元件的方式,來實現非static來新增自定義屬性:

1.在自定義類中對新增自定義屬性的非static方法,新增@BindingAdapter註解


2.建立自定義元件類,實現DataBindingComponent。這時會自動報錯,提示需要實現獲取1中類的方法(靜態的就不需要了)。那就實現此方法


3.把元件物件設定給DataBinding


程式碼實現:

2.8.1 自定義類中新增非static方法,用於新增自定義屬性

public class NotStaticUtils {
    @BindingAdapter({"imgSrc"})
    public  void showImg(ImageView imageView, String src) {
        if (src == null) {
            imageView.setImageResource(R.mipmap.ic_launcher);
        } else {
            Glide.with(imageView.getContext()).load(src).into(imageView);
        }
    }
}


2.8.2 建立自定義元件類,並實現方法

public class MyComponent implements DataBindingComponent{
    private NotStaticUtils utils;

    @Override
    public NotStaticUtils getNotStaticUtils() {
        if (utils == null) {
            utils = new NotStaticUtils();
        }
        return utils;
    }
}


2.8.3 把自定義元件設定給DataBinding

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // 方法一、設定預設的元件
    DataBindingUtil.setDefaultComponent(new MyComponent());

    ActivityNotStaticBinding dataBinding = DataBindingUtil.setContentView(this, R.layout.activity_not_static);

    // 方法二、直接在構造中傳入,這裡是單獨地給本DataBinding指定自定義元件
    // ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main, new Component());

    dataBinding.setSrc1("http://avatar.csdn.net/4/9/8/1_a10615.jpg");
    dataBinding.setSrc2(null);
}


2.8.4 xml中使用
這個跟上面一樣,就是名稱改了一下而已。核心如下:

<variable
    name="src1"
    type="String" />

    ...

    <!--使用自定義屬性imgSrc-->
    <ImageView
        ...
        app:imgSrc="@{src1}" />


2.9 在Fragment中使用


Fragment都有獨立的佈局,好像與Activity沒有什麼關係,但DataBinding中有一個方法可以繫結View:DataBindingUtil.bind(View root)

2.9.1 佈局檔案

<layout ...>
    <data>
        <variable name="province" type="String" />
        <variable name="city" type="String" />
    </data>

    <LinearLayout ...>
        <TextView ...
            android:text="@{province}" />

        <TextView ...
            android:text="@{city}" />
    </LinearLayout>
</layout>


2.9.2 Fragment中繫結
獲取DataBinding的方式有三種:

1.在onCreateView通過inflate(),然後通過getRoot()返回View。然後直接設定data變數值。
2.通過bind()方法,返回佈局Binding(根據佈局自動生成的)。然後直接設定data變數值。
3.通過bind()方法,返回佈局Binding的父類ViewDataBinding。然後通過setVariable()給指定變數設定值。

private FragmentShowBinding mBinding;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment_show, container, false);
    // 或,在這裡獲取DataBinding
//        mBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_show, container, false);
//        return mBinding.getRoot();
}

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);

    // 繫結View
    mBinding = DataBindingUtil.bind(view);
    mBinding.setProvince("浙江");
    mBinding.setCity("寧波");

    // 或,獲取父類ViewDataBinding,然後通過設定變數的方法
//        ViewDataBinding binding = DataBindingUtil.bind(view);
//        binding.setVariable(BR.province, "江西");
//        binding.setVariable(BR.city, "贛州");
}


2.10 RecyclerView


RecyclerView跟ListView一樣,有一個介面卡Adapter。但要正常顯示,RecyclerView還需要一個LayoutManager(第一次就不小心就掉此坑了)。

網上有的方法是隻在item條目裡使用Databinding,RecyclerView還是通過findViewById來獲取。但這裡是Databinding,所以我這裡就不要findViewById了。

在Databinding的世界裡,如果這個View有setter方法,直接使用即可,沒有我們可以自定義屬性(見2.6)。比如要新增分割線,自己去玩吧。

直接看程式碼來看步驟邏輯:

2.10.1 activity中的佈局
activity_recycler_view.xml

<?xml version="1.0" encoding="utf-8"?>
<layout ...>

    <data >
        <variable
            name="rvLayoutManager"
            type="android.support.v7.widget.LinearLayoutManager" />
        <variable
            name="rvAdapter"
            type="com.zjun.databinding.demo.adapter.RVAdapter" />
        <!--或:type="android.support.v7.widget.RecyclerView.Adapter" />-->
    </data>

    <RelativeLayout ...>

        <android.support.v7.widget.RecyclerView
            ...
            app:layoutManager="@{rvLayoutManager}"
            app:adapter="@{rvAdapter}"
            />
    </RelativeLayout>
</layout>


2.10.2 item條目佈局
跟上面ListView的條目佈局一樣 
item_recycler_view.xml

<?xml version="1.0" encoding="utf-8"?>
<layout ...>

    <data>
        <variable name="member" type="com.zjun.databinding.demo.bean.Member" />
    </data>

    <LinearLayout ...>

        <ImageView ...
            app:imageUrl="@{member.icon}" />

        <TextView ...
            android:text="@{member.name}" />
    </LinearLayout>
</layout>


2.10.3 介面卡及Activity中的程式碼


有兩種寫法,第一種是官方的,第二種通用性好。官方的裡面,條目佈局都不用。


一、官方辦法

public class RVAdapter extends RecyclerView.Adapter<RVAdapter.RVHolder> {
    private Context mContext;
    private List<Member> mDataList;

    public RVAdapter(Context context, List<Member> list) {
        this.mContext = context;
        this.mDataList = list;
    }

    @Override
    public RVHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return RVHolder.create(LayoutInflater.from(mContext), parent);
    }

    @Override
    public void onBindViewHolder(RVHolder holder, int position) {
        holder.bindTo(mDataList.get(position));
    }

    @Override
    public int getItemCount() {
        return mDataList == null ? 0 :mDataList.size();
    }

    static class RVHolder extends RecyclerView.ViewHolder {
        // 建立一個靜態獲取方法
        static RVHolder create(LayoutInflater inflater, ViewGroup parent) {
            ItemRecyclerViewBinding binding = ItemRecyclerViewBinding.inflate(inflater, parent, false);
            return new RVHolder(binding);
        }

        ItemRecyclerViewBinding mBinding;

        private RVHolder(ItemRecyclerViewBinding binding) {
            super(binding.getRoot());
            this.mBinding = binding;
        }

        public void bindTo(Member member) {
            mBinding.setMember(member);
            // 它使資料繫結重新整理所有掛起的更改。這官方的解釋好難懂,其實功能就是讓資料立即展示在佈局上
            mBinding.executePendingBindings();
        }
    }
}


activity中使用:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    ActivityRecyclerViewBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_recycler_view);

    // 模擬資料
    List<Member> list = new ArrayList<>();
    for (int i = 0; i < 100; i++) {
        // 1個網路圖片1個本地圖片,依次迴圈
        Member member = new Member("user" + i, (i & 0x01) == 0 ? "http://avatar.csdn.net/4/9/8/1_a10615.jpg" : null);
        list.add(member);
    }

    // 設定佈局管理器,及介面卡
    binding.setRvLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
    binding.setRvAdapter(new RVAdapter(this, list));
}


二、通用辦法

activity中把setAdapter()程式碼,改成這句這就好了:

binding.setRvAdapter(new RVAdapter(this, list, R.layout.item_recycler_view, BR.member));


三、常見坑


DataBinding的錯誤很難找,但基本都是在xml檔案中出錯的。要仔細

3.1 Error:(8, 45) 錯誤: 程式包com.zjun.databinding.demo.databinding不存在


四、開源Demo

點我傳送~

 

本文參考自:a10615 博主的部落格,感謝分享,支援開源,共同進步。