Android Jetpack DataBinding入門填坑(三)

Jetpack系列
Android Jetpack WorkManager初級認識
Android Jetpack ViewModel由淺入深

附上官網地址https://developer.android.com/topic/libraries/data-binding/expressions

一、DataBinding的定義及作用

是一個支持庫秃踩,使用該庫衬鱼,您可以使用聲明性格式而非編程方式將布局中的UI組件綁定到應用程序中的數據源。不需要在使用findViewById之類的憔杨,布局文件也不再簡單的是一個布局文件鸟赫,可以包含數據以及邏輯。

配置必要信息

Build.gradle文件添加下面信息

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

二、基本使用

1. 簡單展示綁定過程
  1. 新建activity_databinding.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
  // 定義數據的標簽
    <data>
        <variable
            name="title"
            type="String" />
    </data>
 // 定義布局的標簽
<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
   >
    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="48dp"
        android:text="@{title}"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

上面的格式:<layout></layout>包含兩個子標簽抛蚤,

  1. <data></data>定義我們的數據的地方台谢,
  2. <ConstraintLayout></ConstraintLayout>,這個布局就相當于我們平時的布局岁经。
    TextViewtext綁定了android:text="@{title}"朋沮,如果第一次設置title數據變化,頁面就會跟著變化缀壤。

這里解釋一下<variable/>標簽中的屬性樊拓,
name是定義的變量名
type是變量的類型

  1. 新建Acitivity綁定布局
class DatabasingActivity : AppCompatActivity() , View.OnClickListener {


    lateinit var mactivityBinding: ActivityDatabindingBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //綁定布局
        mactivityBinding = DataBindingUtil.setContentView(this,R.layout.activity_databinding)
        mactivityBinding.title = "基礎使用"
    }
}

上面的ActivityDatabindingBinding是系統(tǒng)自動幫我們生成的,使用DataBindingUtil.setContentView(this,R.layout.activity_databinding)便可以綁定好布局诉位,(不需要像以前調用setContentView()),mactivityBinding.title = "基礎使用"賦值給title,textView就會自動展示出數據了骑脱。

注意點:

  1. ActivityDatabindingBinding是根據你的布局.xml去生成的 這里的是activity_databinding.xml所以生成ActivityDatabindingBinding.
  2. 如果發(fā)現databinding生成的ActivityDatabindingBindingImpl(看自己的命名)中出現路徑報錯,那么最大的可能性是你的.xml文件里面寫錯了之類的2钥贰Hァ!

下面看一下.xml文件支持什么表達式岳瞭。

三拥娄、支持的表達式:

  • 數學計算符 + - / * %
  • 字符連接符號 +
  • 邏輯運行符號 && ||
  • 二元運行符號 & | ^
  • 一元運行符號 + - ! ~
  • 移位 >> >>> <<
  • 比較符號 == > < >= <=(請注意,<必須轉義為&lt;)
  • instanceof
  • Grouping ()
  • character, String, numeric, null
  • cast
  • 方法調用
  • 現場訪問
  • Array存取 []
  • 三元運算符 ?:

四瞳筏、 不支持的表達式:

  • this
  • super
  • new
  • explicit generic invocation (顯式泛型調用)

五稚瘾、 設置點擊事件跟導入數據類

  1. 新建數據實體類
data class Person(var Name:String,var Age:Int)
  1. 修改一下布局文件
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
      //關鍵點1
        <import type="testview.zhen.com.myapplication.bean.Person"/>
       //關鍵點2
        <variable
            name="peronInfo"
            type="Person" />
     //關鍵點3
        <variable
            name="onClickListener"
            type="android.view.View.OnClickListener" />
        <variable
            name="title"
            type="String" />
    </data>
<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
   >

    <TextView
        android:id="@+id/text_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="172dp"
        android:text="@{peronInfo.name,default=預覽}"
        app:layout_constraintTop_toTopOf="parent"
        tools:layout_editor_absoluteX="-16dp" />
//關鍵點4
    <TextView
        android:id="@+id/textView2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@{String.valueOf(peronInfo.age),default=預覽}"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/text_view" />
//關鍵點4
    <Button
        android:id="@+id/button7"
        android:layout_width="159dp"
        android:layout_height="46dp"
        android:layout_marginTop="56dp"
        android:onClick="@{onClickListener}"
        android:text="點擊1"
        app:layout_constraintEnd_toStartOf="@+id/button8"
        app:layout_constraintHorizontal_bias="0.451"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView2" />

    <Button
        android:id="@+id/button8"
        android:layout_width="159dp"
        android:layout_height="46dp"
        android:layout_marginTop="56dp"
        android:layout_marginEnd="36dp"
        android:onClick="@{onClickListener}"
        android:text="點擊2"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView2" />

</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

關鍵代碼1:<import type="testview.zhen.com.myapplication.bean.Person"/> 導入數據類所在的路徑包名,要導入后才能使用
關鍵代碼2:定義Person類型的變量
關鍵代碼3:定義android.view.View.OnClickListenerView的點擊事件
關鍵代碼4:在Buttonandroid:onClick="@{onClickListener}中引用關鍵代碼3定義的點擊事件
3 修改一下Activity文件

class DatabasingActivity : AppCompatActivity() , View.OnClickListener {


    lateinit var mactivityBinding: ActivityDatabindingBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //綁定布局
        mactivityBinding = DataBindingUtil.setContentView(this,R.layout.activity_databinding)
        //賦值給布局中定義的<data>中的面的peronInfo
        mactivityBinding.peronInfo = Person("man",18)
        //實現布局中定義的<data>中的onClickListener變量,這里傳入this,記得要實現接口
        mactivityBinding.onClickListener = this
    }
    //當點擊按鈕的時候就會自動調用到這里了
    override fun onClick(v: View?) {
        when(v){
            mactivityBinding.button7 -> {
                mactivityBinding.textView.text = "這個是點擊button7產生的"
            }
            mactivityBinding.button8 ->{
                mactivityBinding.textView2.text = "這個是點擊button8產生的"
            }
        }
    }
}

直接看上面注釋就知道用法了

上面的注釋看懂就可以了,Activity中基本的DataBinding你就算是掌握了,關于點擊事件的還有很多種寫法姚炕,可能需要重新寫一篇詳細的說一下其它的細節(jié)吧摊欠。

六、在Fragment中使用

    lateinit var fragmentTestBinding:FragmentTestBindingBinding
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        fragmentTestBinding = DataBindingUtil.inflate(inflater,R.layout.fragment_test_binding,container,false)
        return fragmentTestBinding.root
    }

Activity對比Fragment這里就是DataBindingUtil.inflate()傳參不同柱宦,然后返回fragmentTestBinding.root些椒。其它的操作都是一樣的

七、單向綁定數據(可觀察的數據對象)

最開始使用的時候我很不理解為什么還有個單向綁定掸刊。因為我看到基本類型的數據免糕,在xmldata定義 然后再Activity中更改,頁面會跟著一起刷新忧侧,這不就是相當于單向綁定了嗎石窑??蚓炬?直到后面我在<data>節(jié)點中import入自定義的數據類bean松逊,然后再在Activity中更改bean中的成員變量時,頁面并沒有改變肯夏。這時候我才懂了這個存在的原因经宏。(ps:這個只是個人剛接觸的時候想法楼咳,新手有可能也有會這樣想法,我這里先說一下)

官網定義:任何普通的舊對象都可以用于數據綁定烛恤,但是修改對象不會自動導致UI更新母怜。數據綁定可用于使您的數據對象在數據更改時通知其他對象(稱為偵聽器)。有三種不同類型的可觀察類: 對象缚柏,字段和集合

實現的基本方法有以下幾種

1. 直接定義可監(jiān)聽變量
  • ObservableBoolean
  • ObservableByte
  • ObservableChar
  • ObservableShort
  • ObservableInt
  • ObservableLong
  • ObservableFloat
  • ObservableDouble
  • ObservableParcelable
//定義的實體bean時候
class Person {
    val Name = ObservableField<String>()
    val Age = ObservableInt()
}
//(kotlin 語法 )調用實體bean的時候
user.firstName = "Google"
val age = person.Age 
--------------------------------------------------------
//(java 語法 )調用實體bean的時候
person.firstName.set("Man");
int age = person.Age.get();

使用的時候記得使用get(),set()方法苹熏。(ps:kotlin語法看來起來是直接調用的,但實際上里面也是實現了get()set()方法)

//可監(jiān)聽變量數組類型

  • ObservableArrayMap<>()
  • ObservableArrayList<>()

----------定義xml文件-----------------------
<data>
        <import type="androidx.databinding.ObservableArrayList"/>
        <variable
            name="list"
            type="ObservableArrayList&lt;String>" />
</data>
…

<TextView
    android:text='@{list[0],defualt = "hello"}'
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>
}
------------使用的時候----------------------------

ObservableArrayList<String>().apply {
    add("man")
}

用法跟基本類型一致币喧,但是有兩點要注意

  1. 記得在<data>import入對應的數組的包名所在路徑
  2. 引用這些集合類型的時候轨域,<要改為\&lt; (ps:Android stuido會提醒你這樣子操作的 )
2. ObservableField<T>,這個跟上面那些用法一樣杀餐,泛型傳入指定類型干发。
3. 繼承 BaseObservable()
-------------------------------kotlin寫法-----------------------------
class User :BaseObservable(){
    @get:Bindable
    var name:String = ""
    set(value) {
        field = value
        notifyPropertyChanged(BR.name)
    }
    @get:Bindable
    var age:Int = 0
    set(value) {
        field = value
        notifyPropertyChanged(BR.age)
    }
}
--------------------------------java寫法---------------------------------
private static class User extends BaseObservable {
    private String firstName;
    private String lastName;

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

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

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

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

實體類繼承BaseObservable()

  1. 在對應的字段get方法錢前面加上注解@Bindable ,kotlin@get:Bindable
  2. set方法中修改數據后調用notifyPropertyChanged(BR.name)通知更改數據
  3. 如果數據類的基類不能被改變,可觀察到的界面可以實現使用PropertyChangeRegistry對象注冊和通知監(jiān)聽器。(補充)

這里有個坑J非獭M鞒ぁ! BR總是報錯 找不到nameage字段琼讽,后來百度需要在對應module項目下的build.gradle上面加上插件

apply plugin: 'kotlin-kapt'

八必峰、雙向綁定數據

在xml文件中 單向綁定我們是用@{變量名},雙向綁定則是@={變量名}
最常見的需求就是我們的頁面輸入了。輸入的數據要在代碼中可以讓我們接收到钻蹬。

 <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:text="@{title,default =標題}"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/editText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="28dp"
        android:ems="10"
        android:inputType="textPersonName"
        android:text="@={title}"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView3" />

editText數據數據的時候android:text="@={title}"雙向綁定數據吼蚁,TextView中綁定的 android:text="@{title,default =標題}"也會跟著一起變化。

九问欠、在include中使用

在include中:
先定義include_text.xml

<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <import type="testview.zhen.com.myapplication.bean.Person"/>
        <variable
            name="peronInfo"
            type="Person" />
    </data>
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@{`嵌套布局 用戶名:`+peronInfo.name}"
        />
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@{`嵌套布局 年齡:`+peronInfo.age}"
        />
</LinearLayout>
</layout>

在布局中引入

<layout xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
        <variable
            name="peronInfo"
            type="Person" />
    </data>
<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
   >

    <include
        layout="@layout/inclue_text"
        app:peronInfo = "@{peronInfo}"
        />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

include標簽中app:peronInfo將數據傳入允蜈,這里的peronInfo是在include布局中我們自己定義的數據问词。

十蚀狰、在viewStub中使用

因為viewStub是屬于懶加載的布局邻悬,如果不調用inflate捺癞,就不會加載猾瘸。屬于安卓上面也是頁面優(yōu)化有一個范疇蓉媳。

先定義一個viewStub布局頁面

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <import type="testview.zhen.com.myapplication.bean.Person"/>
        <variable
            name="peronInfo"
            type="Person" />
    </data>
<LinearLayout
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@{peronInfo.name + peronInfo.age}"
        />
</LinearLayout>
</layout>

在布局中引入

<layout xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
        <variable
            name="peronInfo"
            type="Person" />
    </data>
<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
   >

    <ViewStub
            android:id="@+id/view_stub"
            android:layout_width="match_parent"
            android:layout_height="80dp"
            android:layout="@layout/viewstub_layout"
            app:peronInfo = "@{peronInfo}"
            />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

以上的操作跟include的用法一致,不同點在于Activity中的綁定
Activity

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //綁定布局
        mactivityBinding = DataBindingUtil.setContentView(this,R.layout.activity_databinding)
        o.add(0,"第一數據")
        mactivityBinding.peronInfo = Person("man",18,o)
        mactivityBinding.viewStub.viewStub!!.inflate()
    }

關鍵代碼mactivityBinding.viewStub.viewStub!!.inflate()這里就是加載viewStub的地方蜕乡。

十一嫁怀、在Adapter中的使用

簡化統(tǒng)一可以使用的ViewHolder

public class BaseViewHolder extends RecyclerView.ViewHolder {
    public BaseDataBinding mbinding;

    public BaseViewHolder(BaseDataBinding binding) {
        super(binding.getRoot());
        mbinding = binding;
    }
}

你可以使用上面的ViewHolder就可以不用自己總是去寫ViewHolder了设捐。

val listItemBinding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false)

AdapteronCreateViewHolder中可以使用上面的方法綁定布局

關于AdapterDataBinding使用的網上有很多文章大家可以自行查閱

這篇文章主要是記錄一下自己學習的過程,很多細節(jié)化跟封裝的話以后再出一篇文章另外記錄塘淑,有問題的也請同學們在評論區(qū)留言萝招,希望看的同學們覺得有用的話給個贊~ 謝謝

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市存捺,隨后出現的幾起案子槐沼,更是在濱河造成了極大的恐慌曙蒸,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件岗钩,死亡現場離奇詭異纽窟,居然都是意外死亡,警方通過查閱死者的電腦和手機兼吓,發(fā)現死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門臂港,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人视搏,你說我怎么就攤上這事审孽。” “怎么了浑娜?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵佑力,是天一觀的道長。 經常有香客問我筋遭,道長打颤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任漓滔,我火速辦了婚禮瘸洛,結果婚禮上,老公的妹妹穿的比我還像新娘次和。我一直安慰自己反肋,他們只是感情好,可當我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布踏施。 她就那樣靜靜地躺著石蔗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪畅形。 梳的紋絲不亂的頭發(fā)上养距,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天,我揣著相機與錄音日熬,去河邊找鬼棍厌。 笑死,一個胖子當著我的面吹牛竖席,可吹牛的內容都是我干的耘纱。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼毕荐,長吁一口氣:“原來是場噩夢啊……” “哼束析!你這毒婦竟也來了?” 一聲冷哼從身側響起憎亚,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤员寇,失蹤者是張志新(化名)和其女友劉穎弄慰,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體蝶锋,經...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡陆爽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了扳缕。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片墓陈。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖第献,靈堂內的尸體忽然破棺而出贡必,到底是詐尸還是另有隱情,我是刑警寧澤庸毫,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布仔拟,位于F島的核電站,受9級特大地震影響飒赃,放射性物質發(fā)生泄漏利花。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一载佳、第九天 我趴在偏房一處隱蔽的房頂上張望炒事。 院中可真熱鬧,春花似錦蔫慧、人聲如沸挠乳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽睡扬。三九已至,卻和暖如春黍析,著一層夾襖步出監(jiān)牢的瞬間卖怜,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工阐枣, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留马靠,地道東北人。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓蔼两,卻偏偏與公主長得像甩鳄,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子宪哩,可洞房花燭夜當晚...
    茶點故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內容