一、數(shù)據(jù)模型 Model 與視圖 View 雙向綁定
1、數(shù)據(jù)模型 Model 與視圖 View 的單向綁定
在之前的博客中 ,
將 數(shù)據(jù)模型 Model 中的 指定 Field 字段 綁定到 View 視圖中的組件 ,
在實(shí)際案例中 , 將 Student 類中的 String 類型的 name 字段綁定到了 布局文件中的 TextView 組件中 ,
當(dāng) Student#name 字段發(fā)生了改變 ,
對(duì)應(yīng)的 TextView 組件中顯示的內(nèi)容也發(fā)生了相應(yīng)的修改 ;
上述綁定方式可以理解為 單向綁定 ,
因?yàn)?TextView 組件不能修改 , 只能顯示 ,
數(shù)據(jù)模型中的字段修改 , 可以改變 TextView 顯示的內(nèi)容 ;
TextView 組件不能發(fā)起對(duì)數(shù)據(jù)模型的修改 ;
2、由單向綁定引出雙向綁定
如果 綁定的 數(shù)據(jù)模型 對(duì)應(yīng)的組件是 EditText 文本框 ,
EditText 組件的內(nèi)容可以自行進(jìn)行修改 ,
數(shù)據(jù)模型 可以發(fā)起對(duì) EditText 組件的修改 ,
同時(shí) EditText 也可以發(fā)起對(duì)數(shù)據(jù)模型的修改 ,
那么就會(huì)出現(xiàn)一個(gè) 雙向綁定 的問(wèn)題 ;
二、BaseObservable 實(shí)現(xiàn)數(shù)據(jù)模型 Model 與視圖 View 雙向綁定
示例代碼 : https://download.csdn.net/download/han1202012/87702558
1、啟用 DataBinding
使用 DataBinding 前 , 必須啟用數(shù)據(jù)綁定 ,
在 Module 下的 build.gradle 構(gòu)建腳本 中 , 在 " android / defaultConfig " 層級(jí) , 配置
// 啟用 DataBinding
dataBinding {
enabled = true
}
內(nèi)容 , 即可啟用 數(shù)據(jù)綁定 ;
完整層級(jí)的代碼如下 :
android {
namespace 'kim.hsl.databinding_demo'
compileSdk 32
defaultConfig {
applicationId "kim.hsl.databinding_demo"
minSdk 21
targetSdk 32
// 啟用 DataBinding
dataBinding {
enabled = true
}
}
}
2、導(dǎo)入 kotlin-kapt 插件
凡是 在 Kotlin 中使用到注解的情況下 , 都需要導(dǎo)入 kotlin-kapt 插件 ;
在 Module 下的 build.gradle 構(gòu)建腳本中 , 導(dǎo)入 kotlin-kapt 插件 ;
plugins {
id 'kotlin-kapt'
}
3、數(shù)據(jù)模型類
數(shù)據(jù)類中 , 主要 封裝 數(shù)據(jù)模型 ;
package kim.hsl.databinding_demo
class Student(var name: String, var age: Int) {
}
4、BaseObservable 實(shí)現(xiàn)雙向綁定 ( 本博客的核心重點(diǎn) ) ★
實(shí)現(xiàn) 數(shù)據(jù) 與 視圖 的雙向綁定類 , 需要繼承 BaseObservable
類 ;
class StudentViewModel: BaseObservable {
}
在該類中 , 需要 維護(hù)一個(gè) 數(shù)據(jù)類對(duì)象 , 如下在 次構(gòu)造函數(shù) 中傳入 ;
lateinit var student: Student
constructor() {
this.student = Student("Tom", 18)
}
實(shí)現(xiàn)一個(gè) getXxx 函數(shù) , 使用 @Bindable
注解修飾該函數(shù) ,
同時(shí) 在 DataBinding 布局中 , 為 EditText 組件設(shè)置值時(shí) , 也使用該函數(shù)設(shè)置值 ;
設(shè)置了 @Bindable
注解 , 只要 student 對(duì)象中的 name 發(fā)生了變化 , 綁定的組件中的內(nèi)容就會(huì)發(fā)生變化 ;
/**
* 只要 student 對(duì)象中的 name 發(fā)生了變化
* 綁定的組件中的內(nèi)容就會(huì)發(fā)生變化
*/
@Bindable
fun getStudentName(): String {
return student.name
}
如果要實(shí)現(xiàn) 通過(guò) EditText 修改 數(shù)據(jù)模型 的效果 , 需要再實(shí)現(xiàn)一個(gè) setXxx 函數(shù) ,
該函數(shù)需要與之前的 使用 @Bindable
注解修飾的 getXxx 函數(shù)對(duì)應(yīng) , Xxx 必須是一樣的 ;
修改后需要調(diào)用 notifyPropertyChanged(BR.xxx) 通知數(shù)據(jù)模型進(jìn)行變更 ;
/**
* 只要綁定的 EditText 組件內(nèi)容發(fā)生變化
* 就會(huì)自動(dòng)調(diào)用該函數(shù) 修改 student 對(duì)象中的 name 字段
*/
fun setStudentName(name: String): Unit {
// 修改后的字符串不為空 且與之前的值不同 才更新數(shù)據(jù)模型數(shù)據(jù)
if (name != null && !(name == student.name)) {
student.name = name
Log.i("StudentViewModel", "setStudentName : ${name}")
// BR 是編譯時(shí)自動(dòng)生成的字段
// studentName 對(duì)應(yīng)的是 上面 被 @Bindable 修飾的 getStudentName 函數(shù)
notifyPropertyChanged(BR.studentName)
}
}
BR 類是 BaseObservable
子類中由 @Bindable
注解修飾的函數(shù)生成 ;
BR 類生成位置在 app\build\generated\source\kapt\debug\kim\hsl\databinding_demo\BR.java
;
BaseObservable 類源碼如下 :
package kim.hsl.databinding_demo
import android.util.Log
import android.view.View
import androidx.databinding.BaseObservable
import androidx.databinding.Bindable
class StudentViewModel: BaseObservable {
lateinit var student: Student
constructor() {
this.student = Student("Tom", 18)
}
/**
* 只要 student 對(duì)象中的 name 發(fā)生了變化
* 綁定的組件中的內(nèi)容就會(huì)發(fā)生變化
*/
@Bindable
fun getStudentName(): String {
return student.name
}
/**
* 只要綁定的 EditText 組件內(nèi)容發(fā)生變化
* 就會(huì)自動(dòng)調(diào)用該函數(shù) 修改 student 對(duì)象中的 name 字段
*/
fun setStudentName(name: String): Unit {
// 修改后的字符串不為空 且與之前的值不同 才更新數(shù)據(jù)模型數(shù)據(jù)
if (name != null && !(name == student.name)) {
student.name = name
Log.i("StudentViewModel", "setStudentName : ${name}")
// BR 是編譯時(shí)自動(dòng)生成的字段
// studentName 對(duì)應(yīng)的是 上面 被 @Bindable 修飾的 getStudentName 函數(shù)
notifyPropertyChanged(BR.studentName)
}
}
}
5、布局文件設(shè)置 ( 重點(diǎn) )
在 DataBinding 布局文件中 , 需要 在 " data / variable " 標(biāo)簽中 , 引入 StudentViewModel 類型的對(duì)象 ;
在位 EditText 組件賦值時(shí) , 需要使用 android:text="@={student.studentName}"
進(jìn)行賦值 , 注意值為 @={student.studentName}
, 比之前的數(shù)據(jù)綁定多了一個(gè)等號(hào) ;
布局代碼示例 :
<?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">
<data>
<variable
name="student"
type="kim.hsl.databinding_demo.StudentViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<EditText
android:id="@+id/imageView"
android:layout_width="100dp"
android:layout_height="100dp"
android:text="@={student.studentName}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
6、Activity 組件代碼 ( 重點(diǎn) )
在 Activity 組件中 , 向布局中設(shè)置的對(duì)象類型是 StudentViewModel 類型的 , 不是 Student 類型的 ;
package kim.hsl.databinding_demo
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import kim.hsl.databinding_demo.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 設(shè)置布局文件
// 布局文件是 activity_main.xml
// 該類名稱生成規(guī)則是 布局文件名稱 + Binding
var activityMainBinding: ActivityMainBinding =
DataBindingUtil.setContentView(this, R.layout.activity_main)
// 為布局 設(shè)置 數(shù)據(jù)
activityMainBinding.student = StudentViewModel()
}
}
7、執(zhí)行結(jié)果
執(zhí)行后顯示 :
逐個(gè)字母刪除 Tom , 然后輸入 Jack ;
最終打印如下日志 :
setStudentName : To
setStudentName : T
setStudentName :
setStudentName : Jack
三、ObservableField 實(shí)現(xiàn)數(shù)據(jù)模型 Model 與視圖 View 雙向綁定 ( 本博客的核心重點(diǎn) ) ★
示例代碼 :
ObservableField 實(shí)現(xiàn)數(shù)據(jù)模型 Model 與視圖 View 雙向綁定
與
BaseObservable 實(shí)現(xiàn)數(shù)據(jù)模型 Model 與視圖 View 雙向綁定
進(jìn)行對(duì)比 ,
除了 StudentViewModel 之外 , 其它代碼都一樣 ;
重點(diǎn)介紹 StudentViewModel 類 ;
將數(shù)據(jù)模型類 Student , 定義為 ObservableField 的泛型類 ;
lateinit var studentObservableField: ObservableField<Student>
在構(gòu)造函數(shù)中 , 創(chuàng)建 Student 對(duì)象 , 將其設(shè)置到 ObservableField<Student>
對(duì)象中 ;
constructor() {
var student: Student = Student("Tom", 18)
studentObservableField = ObservableField()
studentObservableField.set(student)
}
定義 getStudentName()
函數(shù) , 獲取 ObservableField<Student>
對(duì)象中的 Student
對(duì)象的 name
屬性 ;
fun getStudentName(): String? {
return studentObservableField.get()?.name
}
定義 setStudentName()
函數(shù) , 設(shè)置 ObservableField<Student>
對(duì)象中的 Student
對(duì)象的 name
屬性 ;
fun setStudentName(name: String): Unit {
studentObservableField.get()?.name = name
Log.i("StudentViewModel", "setStudentName : ${name}")
}
完整代碼如下 :文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-420395.html
package kim.hsl.databinding_demo
import android.util.Log
import androidx.databinding.ObservableField
class StudentViewModel {
lateinit var studentObservableField: ObservableField<Student>
constructor() {
var student: Student = Student("Tom", 18)
studentObservableField = ObservableField()
studentObservableField.set(student)
}
fun getStudentName(): String? {
return studentObservableField.get()?.name
}
fun setStudentName(name: String): Unit {
studentObservableField.get()?.name = name
Log.i("StudentViewModel", "setStudentName : ${name}")
}
}
執(zhí)行上述代碼 , 也能實(shí)現(xiàn)與 BaseObservable 雙向綁定相同的效果 ;文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-420395.html
到了這里,關(guān)于【Jetpack】DataBinding 架構(gòu)組件 ⑤ ( 數(shù)據(jù)模型與視圖雙向綁定 | BaseObservable 實(shí)現(xiàn)雙向綁定 | ObservableField 實(shí)現(xiàn)雙向綁定 )的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!