gradle plugin version:7.2.1
gradle version:7.3.3
android studio version:Chipmunk 2021.2.1 Patch 1
|app
|build.gradle
|build.gradle
在app/build.gradle里的最顶部。
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'kotlin-kapt`//这是添加的
}
android {
...
kapt {
includeCompileClasspath = false
}
buildFeatures {
viewBinding true
//如果需要下面就取消注释
//dataBinding true
}
}
viewBinding和dataBinding区别:
viewBinding不用在布布局文件转换局文件里额外包裹标签,直接可以在代码里调用和加载。
dataBinding使用可以将普通布局文件的第一行点击小灯泡转换为该形式,这样的可以使用<标签,直接在布局里绑定页面数据和如点击事件之类的方法。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
LinearLayout>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
LinearLayout>
layout>
旧:setContentView(R.layout.activity_main)
新:ActivityMainBinding.inflate(layoutInflater)
,注意这里是kotlin写法,java为ActivityMainBinding.inflate(getLayoutInflater())
这样子。
fragment里类似,只要有个layoutInflater,就可以初始化个布局。
val binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
这样,获取里面的子view也很方便。
假定布局内有一个TextView:
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
LinearLayout>
layout>
要在代码里设置文本。
旧:findViewById
新:binding.Text.text="321"
这是DataBinding才有的
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="str"
type="java.lang.String" />
data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{str}" />
LinearLayout>
layout>
//别忘了在setContentView()差不多那些位置绑定该参数,不然就会报错。
//如果没有BR这个类或者BR.str标红,构建一下就好
binding.setVariable(BR.str, "321")
适用于EditText这样的,使用双向绑定text可以在代码里实例化一个text,之后EditText内容改变该text也会改变,相当于不用再获取EditText的text。
使用示例:
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="str"
type="java.lang.String" />
<variable
name="edt"
type="java.lang.String" />
data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{str}" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:text="@={edt}" />
LinearLayout>
layout>
//同样别忘记
var edt = "123"
binding.setVariable(BR.edt, edt)
//之后直接调用edt就可以得到EditText内容。
适用于按钮点击事件的绑定,还是偏向于在Activity里代码方式更方便操作,在下面viewmodel说明。
一个activity可以绑定有多个ViewModel,ViewModel相当于是复杂业务逻辑比如加减法计算、网络请求等放置的好地方。可以一个ViewModel负责一个方面,比如一个是负责网络请求,一个是负责页面展示数据这样子。
ViewModel好处在于可以跟着activity共存亡,我理解是这样。
使用需要在app/build.gradle里添加一个:implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1"
。
然后就可以新建类继承ViewModel类就行。
在activity里通过ViewModelProvider(owner, ViewModelProvider.NewInstanceFactory()).get(MyViewModel::class.java)
绑定
这里通过ViewModel来绑定前面所说的那些:
//先展示一个方便绑定的方法实现
@Suppress("UNCHECKED_CAST")
fun <T : ViewModel> viewModel(
owner: ViewModelStoreOwner,
viewModel: Class<out ViewModel>
) = lazy {
ViewModelProvider(owner, ViewModelProvider.NewInstanceFactory()).get(viewModel) as T
}
//然后使用方式
private val viewModel by viewModel<MyViewModel>(this, MyViewModel::class.java)
开始使用示例:
class MyViewModel: ViewModel() {
val txt = "321"
var edt = "321"
fun onButtonClick() {
L.i("点击了该按钮")
}
}
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="model"
type="top.heue.certu.activity.MyViewModel" />
data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{model.txt}" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:text="@={model.edt}" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="@{()->model.onButtonClick()}" />
LinearLayout>
layout>
class MainActivity: AppCompatActivity() {
private val binding by lazy{ ActivityMainBinding.inflate(layoutInflater)}
private val viewModel by viewModel<MyViewModel>(this, MyViewModel::class.java)
override fun onCreate() {
super.onCreate()
setContentView(binding.root)
binding.setVariable(BR.model, viewModel)
}
}
函数绑定可以有这样几种形式:
@{() -> model.onButtonClick()}
,onButtonClick
是一个自定义的方法,可以传递参数,因此可以(view) -> model.onButtonClick(view)
,这样onButtonClick
就可以用到view,以view
作点击事件来自哪个按钮的区分;也可以@{model::onButtonClick}
,不带参数。