Android DataBinding框架的基本使用

Demo地址

怎么配置DataBinding

在Module的gradle 文件下车份,AndroidStudio版本不通開啟的方式也不同
AndroidStudio 3.x 版本

android {
   ...  
   dataBinding{
       enabled = true
   }
}

AndroidStudio 4.x 版本(也可以使用3.0的方式開啟哎媚,但是4.0推薦使用下面的方法)

android {
   ...  
   buildFeatures{
       dataBinding = true
   }
}

這里有一個坑萤衰,就是如果子Module配置了DataBinding,必須在主Module也配置

怎么讓一個 View 可以綁定數(shù)據(jù)

<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>

    </data>

    <androidx.appcompat.widget.LinearLayoutCompat
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </androidx.appcompat.widget.LinearLayoutCompat>
</layout>

比原來的layout文件多了layout標(biāo)簽和data標(biāo)簽抚吠,這樣格式的xml布局文件就是一個支持DataBinding的布局文件冀痕,可以通過快捷鍵Alt+Enter鍵來快速生成

DataBinding 中的被觀察者 BaseObservable

如果想要你的UI隨著數(shù)據(jù)的更新而更新,還需要實現(xiàn)BaseObservable

BaseObservable 是一個被觀察者萝毛,UI組件會觀察BaseObservable项阴,如果數(shù)據(jù)發(fā)生了變化,則UI會更新笆包。這里可以把BaseObservable 理解為數(shù)據(jù)的包裝類鲁冯。

看一個簡單的實現(xiàn)

public class UserEntity extends BaseObservable {
    @Bindable
    private String nickname;
    @Bindable
    private String headUrl;

    public UserEntity(String nickname, String headUrl) {
        this.nickname = nickname;
        this.headUrl = headUrl;
    }

    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
        notifyPropertyChanged(BR.nickname);
    }

    public String getHeadUrl() {
        return headUrl;
    }

    public void setHeadUrl(String headUrl) {
        this.headUrl = headUrl;
        notifyPropertyChanged(BR.headUrl);
    }
}

首先數(shù)據(jù)類實現(xiàn)BaseObservable,然后對需要被觀察的數(shù)據(jù)用@Bindable注解
重寫set/get 方法色查,然后在set 方法(數(shù)據(jù)更新的地方)調(diào)用notifyPropertyChanged(BR.id)薯演,UI就會被通知刷新UI

BR.id是DataBinding生成的id,用來區(qū)分數(shù)據(jù)的id秧了,如果BR下面沒有你的id跨扮,先檢查一個有沒有注解,然后再Rebuild 一下

單向綁定

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

    <data>
        <variable
            name="userInfo"
            type="com.xiaoyu.mvvmdemo.UserEntity" />
    </data>

    <androidx.appcompat.widget.LinearLayoutCompat
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_horizontal"
        android:orientation="vertical">

        <androidx.appcompat.widget.AppCompatTextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:text="@{userInfo.nickname}" />

        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/nickname_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:text='@{"昵稱:"+userInfo.nickname}' />
    </androidx.appcompat.widget.LinearLayoutCompat>
</layout>

單向綁定的話比較簡單,通過@{}的方式就可以把數(shù)據(jù)綁定到UI上了
這里寫了兩個綁定衡创,一個是""帝嗡,一個是'',如果有做字符串操作的(比如例子中的拼接字符串)璃氢,是不能使用""進行綁定的

雙向綁定

雙向綁定相對于單向綁定的語法上來說哟玷,只多了一個=

<EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="請輸入賬號"
        android:text="@={accountNumber}" />

雙向綁定在使用的過程中要注意到一點,就是綁定的這個屬性一也,是否支持雙向綁定巢寡,如果不支持,編譯肯定是不會通過的椰苟。

下面是谷歌實現(xiàn)的雙向綁定

  • AbsListView
    1. android:selectedItemPosition
  • CalendarView
    1. android:date
  • CompoundButton
    1. android:checked
  • DatePicker
    1. android:year
    2. android:month
    3. android:day
  • NumberPicker
    1. android:value
  • RadioGroup
    1.android:checkedButton
  • RatingBar
    1. android:rating
  • SeekBar
    1. android:progress
  • TabHost
    1. android:currentTab
  • TextView
    1. android:text
  • TimePicker
    1. android:hour
    2. android:minute

那么如果說系統(tǒng)提供的綁定方法不能夠?qū)崿F(xiàn)現(xiàn)有的需求怎么辦抑月?這里就需要到下面的自定義綁定方法了

自定義綁定 - 單向綁定

自定義單向綁定比較簡單。只需要一個注解舆蝴,一個方法就可以了
這里寫一個用Glide加載網(wǎng)圖谦絮,并且設(shè)置占位圖的綁定方法

@BindingAdapter(value = {"bindUrl", "bindPlaceholder"}, requireAll = false)
public static void bindUrlAndPlaceholder(ImageView view, String url, int placeholder) {
    Glide.with(view).load(url).apply(new RequestOptions().placeholder(placeholder)).into(view);
}
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <import type="com.xiaoyu.mvvmdemo.R" />

    <variable
            name="userInfo"
            type="com.xiaoyu.mvvmdemo.UserEntity" />
    </data>

    <androidx.appcompat.widget.LinearLayoutCompat
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_horizontal"
        android:orientation="vertical">

        <androidx.appcompat.widget.AppCompatImageView
            bindPlaceholder="@{R.drawable.ic_launcher_background}"
            bindUrl="@{userInfo.headUrl}"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:layout_marginTop="50dp" />

    </androidx.appcompat.widget.LinearLayoutCompat>
</layout>

@BindingAdapter這個注解是用來說明,我這個方法是一個綁定方法注解里需要兩個參數(shù)valuerequireAll
value的類型是一個數(shù)組洁仗,數(shù)組的長度為方法參數(shù)長度-1(去掉View參數(shù))层皱,然后順序一一對應(yīng),bindUrlurl對應(yīng)赠潦,bindPlaceholderplaceholder對應(yīng)叫胖,view即被綁定的View
requireAll這個參數(shù)默認為true,它的意思是祭椰,value里面的數(shù)據(jù)是否全部都要綁定

自定義綁定 - 雙向綁定

單向綁定可以只是set方法臭家,雙向綁定需要做的是,當(dāng)被觀察的View屬性發(fā)生變化的時候方淤,需要把自身的值給更新钉赁。用SwipeRefreshLayout舉一個栗子

    @BindingAdapter("bindIsRefreshing")
    public static void setRefreshing(SwipeRefreshLayout refreshLayout, boolean isRefreshing) {
        if (refreshLayout.isRefreshing() != isRefreshing) {
            refreshLayout.setRefreshing(isRefreshing);
        }
    }

    @InverseBindingAdapter(attribute = "bindIsRefreshing", event = "onRefreshChange")
    public static boolean isRefreshing(SwipeRefreshLayout refreshLayout) {
        return refreshLayout.isRefreshing();
    }

    @BindingAdapter("onRefreshChange")
    public static void setOnRefreshListener(SwipeRefreshLayout refreshLayout, InverseBindingListener inverseBindingListener) {
        refreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                inverseBindingListener.onChange();
            }
        });
    }

setRefreshing這個方法和 單向綁定一樣,不需要多解釋携茂。
isRefreshingsetOnRefreshListener 這兩個方法需要對照著看你踩,
先看isRefreshing這個方法,返回了SwipeRefreshLayout.isRefreshing()讳苦,然后看上面的@InverseBindingAdapter注解带膜,有兩個參數(shù),attribute表示被綁定的屬性鸳谜,我們上面因為是定義的bindIsRefreshing膝藕,所以這里和上面一樣bindIsRefreshing

event這個參數(shù),可以理解為isRefreshing的調(diào)用時機咐扭。這里轉(zhuǎn)到底三個方法setOnRefreshListener,這個方法中的InverseBindingListener是一個DataBinding的接口芭挽,需要在屬性發(fā)生變化時回調(diào)onChange方法滑废,這樣雙向綁定的觀察者就會知道屬性發(fā)生了變化,就會更新自身的屬性值

當(dāng)栗子上的SwipeRefreshLayout觸發(fā)OnRefreshListener.onRefresh時袜爪,會回調(diào)到InverseBindingListener.onChange方法蠕趁,然后觀察者收到回調(diào)后,就會調(diào)用isRefreshing方法來更新屬性

需要注意的是辛馆,雙向綁定中的set方法一定要加屬性值得判斷俺陋,就是當(dāng)屬性相同時,不調(diào)用View的set方法昙篙,避免觸發(fā)死循環(huán)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末腊状,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子瓢对,更是在濱河造成了極大的恐慌寿酌,老刑警劉巖胰苏,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件硕蛹,死亡現(xiàn)場離奇詭異,居然都是意外死亡硕并,警方通過查閱死者的電腦和手機法焰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來倔毙,“玉大人埃仪,你說我怎么就攤上這事∩略撸” “怎么了卵蛉?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長么库。 經(jīng)常有香客問我傻丝,道長,這世上最難降的妖魔是什么诉儒? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任葡缰,我火速辦了婚禮,結(jié)果婚禮上忱反,老公的妹妹穿的比我還像新娘泛释。我一直安慰自己,他們只是感情好温算,可當(dāng)我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布怜校。 她就那樣靜靜地躺著,像睡著了一般注竿。 火紅的嫁衣襯著肌膚如雪茄茁。 梳的紋絲不亂的頭發(fā)上宇智,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機與錄音胰丁,去河邊找鬼随橘。 笑死,一個胖子當(dāng)著我的面吹牛锦庸,可吹牛的內(nèi)容都是我干的机蔗。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼甘萧,長吁一口氣:“原來是場噩夢啊……” “哼萝嘁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起扬卷,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤牙言,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后怪得,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體咱枉,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年徒恋,在試婚紗的時候發(fā)現(xiàn)自己被綠了蚕断。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡入挣,死狀恐怖亿乳,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情径筏,我是刑警寧澤葛假,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站滋恬,受9級特大地震影響聊训,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜夷恍,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一魔眨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧酿雪,春花似錦遏暴、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至醋安,卻和暖如春杂彭,著一層夾襖步出監(jiān)牢的瞬間墓毒,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工亲怠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留所计,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓团秽,卻偏偏與公主長得像主胧,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子习勤,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容