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. 簡單展示綁定過程
- 新建
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>
包含兩個子標簽抛蚤,
-
<data></data>
定義我們的數據的地方台谢, -
<ConstraintLayout></ConstraintLayout>
,這個布局就相當于我們平時的布局岁经。
TextView
的text
綁定了android:text="@{title}"
朋沮,如果第一次設置title
數據變化,頁面就會跟著變化缀壤。
這里解釋一下
<variable/>
標簽中的屬性樊拓,
name
是定義的變量名
type
是變量的類型
- 新建
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
就會自動展示出數據了骑脱。
注意點:
ActivityDatabindingBinding
是根據你的布局.xml
去生成的 這里的是activity_databinding.xml
所以生成ActivityDatabindingBinding
.- 如果發(fā)現
databinding
生成的ActivityDatabindingBindingImpl
(看自己的命名)中出現路徑報錯,那么最大的可能性是你的.xml
文件里面寫錯了之類的2钥贰Hァ!
下面看一下.xml
文件支持什么表達式岳瞭。
三拥娄、支持的表達式:
- 數學計算符 + - / * %
- 字符連接符號 +
- 邏輯運行符號 && ||
- 二元運行符號 & | ^
- 一元運行符號 + - ! ~
- 移位 >> >>> <<
- 比較符號 == > < >= <=(請注意,<必須轉義為<)
- instanceof
- Grouping ()
- character, String, numeric, null
- cast
- 方法調用
- 現場訪問
- Array存取 []
- 三元運算符 ?:
四瞳筏、 不支持的表達式:
- this
- super
- new
- explicit generic invocation (顯式泛型調用)
五稚瘾、 設置點擊事件跟導入數據類
- 新建數據實體類
data class Person(var Name:String,var Age:Int)
- 修改一下布局文件
<?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.OnClickListener
View的點擊事件
關鍵代碼4:在Button
的android: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
些椒。其它的操作都是一樣的
七、單向綁定數據(可觀察的數據對象)
最開始使用的時候我很不理解為什么還有個單向綁定掸刊。因為我看到基本類型的數據免糕,在
xml
中data
定義 然后再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<String>" />
</data>
…
<TextView
android:text='@{list[0],defualt = "hello"}'
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
}
------------使用的時候----------------------------
ObservableArrayList<String>().apply {
add("man")
}
用法跟基本類型一致币喧,但是有兩點要注意
- 記得在
<data>
中import
入對應的數組的包名所在路徑- 引用這些集合類型的時候轨域,
<
要改為\<
(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()
- 在對應的字段
get
方法錢前面加上注解@Bindable
,kotlin
寫@get:Bindable
- 在
set
方法中修改數據后調用notifyPropertyChanged(BR.name)
通知更改數據 - 如果數據類的基類不能被改變,可觀察到的界面可以實現使用
PropertyChangeRegistry
對象注冊和通知監(jiān)聽器。(補充)
這里有個坑J非獭M鞒ぁ! BR總是報錯 找不到
name
跟age
字段琼讽,后來百度需要在對應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)
在Adapter
的onCreateViewHolder
中可以使用上面的方法綁定布局
關于Adapter
的DataBinding
使用的網上有很多文章大家可以自行查閱
這篇文章主要是記錄一下自己學習的過程,很多細節(jié)化跟封裝的話以后再出一篇文章另外記錄塘淑,有問題的也請同學們在評論區(qū)留言萝招,希望看的同學們覺得有用的話給個贊~ 謝謝