Android DataBinding 结合 ViewModel的使用
一、build.gradle引入对应的依赖
在build.gradle(app模块)里引入依赖,然后Sync Now一下:
android {
viewBinding {
enabled = true
}
dataBinding {
enabled = true
}
}
完整的build.gradle代码如下所示:
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}
apply plugin: 'kotlin-kapt'
android {
compileSdk 33
defaultConfig {
applicationId "com.check.databindingproject"
minSdk 23
targetSdk 33
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
viewBinding {
enabled = true
}
dataBinding {
enabled = true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1" // ViewModel 和 LiveData
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.6.1" // LiveData
implementation "androidx.activity:activity-ktx:1.7.0" // 添加 ViewModel KTX 扩展
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
configurations.all {
resolutionStrategy {
force "org.jetbrains.kotlin:kotlin-stdlib:1.8.10"
force "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.10"
}
}
二、转换视图成data binding layout
2、找到想要改为dataBinding视图的页面, Mac系统的按Option Enter (Windows系统的按Alt + Enter)弹出如下:
比如选中的是activity_main.xml视图文件,那么
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
选择这个功能之后,就可以将当前xml文件转换成
<?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>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
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>
整体变成了下面这种布局方式
<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>
</data>
<!-- 布局文件之前的样式 -->
...
</layout>
可以看到页面出现了新的Layout和data的空标签。(data 就是用来存放数据的)
改造之后的完整的代码如下所示:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="user"
type="com.check.databindingproject.UserModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/name_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
tools:text="姓名"
android:text="@{`Name is ` + user.name}" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/name_text"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
tools:text="年龄"
android:text="@{`Age is ` + user.age}" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
其中正常绑定某个变量的值到控件的某个元素上,可以用@{user.age},括号里面用变量替代。然后如果想在里面加上一些常量值,那么就用模板@{`Age is` + user.age}
三、创建ViewModel和Binding对象
3、创建ViewModel类
UserModel.kt
package com.check.databindingproject
import androidx.databinding.BaseObservable
import androidx.databinding.Bindable
class UserModel(user_name: String, user_age: Int) : BaseObservable() {
@get:Bindable
var name: String = user_name
set(value) {
field = value
notifyPropertyChanged(BR.name) // 触发绑定更新
}
@get:Bindable
var age: String = user_age.toString()
set(value) {
field = value
notifyPropertyChanged(BR.age) // 触发绑定更新
}
}
MainViewModel.kt
package com.check.databindingproject
import androidx.lifecycle.ViewModel
class MainViewModel : ViewModel() {
val user = UserModel("Alice", 300)
}
接下来到对应的Activity里,声明全局变量为视图去掉下划线改大写+binding, 比如视图为activity_main.xml,则对应声明的databinding类型变量就是ActivityMainBinding类型,如下:
MainActivity.kt
package com.check.databindingproject
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.ViewModelProvider
import com.check.databindingproject.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var viewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 获取 ViewModel
viewModel = ViewModelProvider(this)[MainViewModel::class.java]
// 使用 DataBinding
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
// 将 ViewModel 的 user 绑定到布局
binding.user = viewModel.user
// 如果你需要动态更改数据,可以直接修改 UserModel 的属性
viewModel.user.name = "Bob"
viewModel.user.age = "1300"
}
}
最后显示出来的效果就是