美文网首页
JetPack<第一篇>:DataBinding

JetPack<第一篇>:DataBinding

作者: NoBugException | 来源:发表于2022-08-08 09:24 被阅读0次

    【1】导入依赖

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

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

    android {
        ...
        dataBinding {
            enabled true
        }
    }
    
    或者 
    
    android {
        ...
        buildFeatures {
            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)
    }
    

    【4】在Activity中使用DataBinding

    mBinding = DataBindingUtil.setContentView(this, R.layout.xxxxx)
    

    或者

    mBinding = XXXXXBinding.inflate(layoutInflater)
    setContentView(mBinding.root)
    

    【5】在Fragment中使用DataBinding

    如果在Fragment中使用,布局是一样的,Fragment代码如下:

    class LoginFragment : Fragment() {
    
        private var binding : FragmentLoginBinding? = null
    
        override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View? {
            // binding = FragmentLoginBinding.inflate(inflater)
            // 或
            binding = DataBindingUtil.inflate(inflater, R.layout.fragment_login, container, false);
            return binding?.root
        }
    
    }
    

    【6】在Adapter中使用

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): 
        RecyclerView.ViewHolder {
            val view = LayoutInflater.from(parent.context).inflate(viewType, parent, false)
            val bidning:RecycleItemProductBinding =  DataBindingUtil.bind(view) 
    }
    

    【7】include 标签的使用

    include 标签不带 merge 标签,需要给 include 标签添加 id, 直接使用 id 即可。

    <include
        android:id="@+id/includeData"
        layout="@layout/layout_include_data_item"/>
    
    binding.includeData.includeTvTitle.setText("")
    

    include 标签带 merge 标签,注意这里和 ViewBinding 用法不一样,给 include 标签添加 id,在 DataBinding 中可以直接使用,在 ViewBinding 中则不行。

    <include
        android:id="@+id/includeDataMerge"
        layout="@layout/layout_merge_data_item"/>
    
    binding.includeDataMerge.mergeTvTitle.setText("通")
    

    【8】ViewStub 标签的使用

    给 ViewStub 标签添加 id, 在 DataBinding 中可以直接使用 id 即可。

    <ViewStub
        android:id="@+id/stub"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout="@layout/view_stub" />
    
    binding.stub.setOnInflateListener { stub, inflated ->
        // DataBinding
        val dataViewStub: ViewStubDataBinding = DataBindingUtil.bind(inflated)!!
        dataViewStub.tvTitle.setText("使用 ViewStub 加载 DataBinding 布局")
    }
                
    if (!binding.stub.isInflated) {
        binding.stub.viewStub!!.inflate()
    } 
    

    [本章完...]

    相关文章

      网友评论

          本文标题:JetPack<第一篇>:DataBinding

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