美文网首页
Data Binding

Data Binding

作者: NoBugException | 来源:发表于2022-07-01 10:55 被阅读0次

【1】导入依赖

implementation 'androidx.databinding:databinding-runtime:4.2.2'

【2】 在app模块下的 build.gradle 文件添加内容

android {
    ...
    dataBinding {
        enabled true
    }
}

或者 

android {
    ...
    buildFeatures {
        viewBinding true
        dataBinding true
    }
}

另外,如果在 android 闭包下没有指定 java 1.8 版本的话,需要添加:

compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
    jvmTarget = '1.8'
}

【3】 布局

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">

    </LinearLayout>
</layout>

layout:用作布局的根节点,只能包裹一个View标签,且不能包裹merge标签
data:Data Binding的数据,只能存在一个data标签

<data class="ActivityMainBinding">

</data>

data 的 class 用来自定义代码中Activity中的ViewBinding使用的<ActivityMainBinding>的名称。


<data> 标签中可以有 <import> 和 <variable> 两大标签:

<data class="ActivityMainBinding">
    <import
        type="com.yunchong.jetpack.model.LoginModel" />
    <variable
        name="loginModel"
        type="LoginModel" />
</data>

import 用于导入一个类,variable  用于定义一个变量,变量 loginModel 需要和 view 绑定:

private lateinit var binding : ActivityMainBinding

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
    val loginModel = LoginModel(this, "zhangsan", "123456");
    binding.loginModel = loginModel
}

当然,setContentView 也有所变化。

import 可以配置别名:

<data class="ActivityMainBinding">
    <import
        alias="LoginModelAlias"
        type="com.yunchong.jetpack.model.LoginModel" />
    <variable
        name="loginModel"
        type="LoginModelAlias" />
</data>

variable 定义的对象在xml中的使用:

<data class="ActivityMainBinding">
    <variable
        name="loginModel"
        type="com.yunchong.jetpack.model.LoginModel" />
</data>

private lateinit var binding : ActivityMainBinding

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
    val loginModel = LoginModel(this, "zhangsan", "123456");
    binding.loginModel = loginModel
}

<?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 class="ActivityMainBinding">
        <variable
            name="loginModel"
            type="com.yunchong.jetpack.model.LoginModel" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
        <TextView
            android:id="@+id/tv_activity_main_account"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:text="账号:"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:textSize="26sp"/>
        <androidx.appcompat.widget.AppCompatEditText
            android:id="@+id/et_activity_main_account"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:textSize="26sp"
            android:hint="输入账号"
            android:onTextChanged="@{() -> loginModel.accountNameChanged()}"
            android:text="@={loginModel.accountNameField.get()}"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintBaseline_toBaselineOf="@id/tv_activity_main_account"
            app:layout_constraintLeft_toRightOf="@id/tv_activity_main_account"/>
        <TextView
            android:id="@+id/tv_activity_main_pwd"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:text="密码:"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/tv_activity_main_account"
            android:textSize="26sp"/>
        <androidx.appcompat.widget.AppCompatEditText
            android:id="@+id/et_activity_main_pwd"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:textSize="26sp"
            android:hint="输入密码"
            android:onTextChanged="@{() -> loginModel.passwordChanged()}"
            android:text="@={loginModel.passwordField.get()}"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintBaseline_toBaselineOf="@id/tv_activity_main_pwd"
            app:layout_constraintLeft_toRightOf="@id/tv_activity_main_pwd"/>

            <androidx.appcompat.widget.AppCompatButton
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingVertical="10dp"
                android:paddingHorizontal="20dp"
                android:textSize="20sp"
                android:enabled="@{(loginModel.accountNameField.get().isEmpty() || loginModel.passwordField.get().isEmpty()) ? false : true}"
                android:onClick="@{() -> loginModel.login()}"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintRight_toRightOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintBottom_toBottomOf="parent"
                android:text="登录"/>

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

在xml布局中使用 `android:text="@{}"` 将数据和view绑定,但仅仅是单向绑定,当数据变化的时候,view 也会跟着改变。
当我们想改变布局中的数据时,只需要变化 model 中的值即可,而不需要主动修改布局中的数据显示;
但是,当布局中的数据发生变化时,model 中数据是无法发生改变的。

为了解决`单向绑定`的弊端,提出了 `双向绑定`。

 `@{}` 是单向绑定, `@={}` 是双向绑定,单向绑定和双向绑定的区别就是有无 `=` 的区别。
双向绑定:当 model 发生变化时,布局中的数据也跟着改变;
          当布局中的数据发生改变时, model 也发生改变。


另外,注意布局中:
android:onTextChanged
android:enabled
android:onClick
的使用。
下面,贴出model代码:

/**
 * 登录Model
 */
class LoginModel(context: Context, accountName : String, password : String) {

    val context: Context = context;
    val accountNameField = ObservableField<String>(accountName)
    val passwordField = ObservableField<String>(password)

    /**
     * 输入账号变化时执行
     */
    fun accountNameChanged() {
        Log.d("yunchong", accountNameField.get() as String)
    }

    /**
     * 输入密码时执行
     */
    fun passwordChanged() {
        Log.d("yunchong", passwordField.get() as String)
    }

    /**
     * 登录
     */
    fun login() {
        if ("zhangsan" == accountNameField.get() && "123456" == passwordField.get()) {
            Toast.makeText(context, "登录成功...", Toast.LENGTH_SHORT).show()
            startActivity<DataActivity>(context) {
                putExtra("acountName", accountNameField.get())
                putExtra("password", passwordField.get())
            }
        } else {
            Toast.makeText(context, "登录失败...", Toast.LENGTH_SHORT).show()
        }
    }
}

Activity 的跳转是被封装好的,直接拿来用即可:

/**
 * 启动 Activity
 */
inline fun <reified T> startActivity(context: Context, block: Intent.() -> Unit) {
    val intent = Intent(context, T::class.java)
    intent.block()
    context.startActivity(intent)
}

[本章完...]

相关文章

网友评论

      本文标题:Data Binding

      本文链接:https://www.haomeiwen.com/subject/bezfbrtx.html