Android Jetpack 学习之旅--> Data Binding 的使用

Posted Kevin-Dev

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Jetpack 学习之旅--> Data Binding 的使用相关的知识,希望对你有一定的参考价值。

介绍

MVVM

MVVM(全称Model-View-ViewModel)同 MVC 和 MVP 一样,是逻辑分层解偶的模式(如果你还不了解 MVC 和 MVP ,建议提前了解一下)。

MVVM 的三要素

  • View 层:xml、Activity、Fragment、Adapter和View等
  • Model 层:数据源(本地数据和网络数据等)
  • ViewModel层:View层处理数据以及逻辑处理。

Data Binding

MVVM 和 Data Binding 是两个不同的概念,MVVM 是一种架构模式,而 Data Binding 是一个实现数据和 UI 绑定的框架,是构建 MVVM 模式的一个工具。

学习资料:
官方文档:Data Binding Library
谷歌实验室:官方教程
官方 Demo 地址:android-databinding

实战

1. 效果图

2. 在 app/build.gradle 文件添加:

android 
...
    dataBinding 
       enabled true
    

3. 构建 LoginModel
LoginModel 主要负责登录逻辑的处理以及两个输入框内容改变的时候数据更新的处理。

class LoginModel constructor(name: String, pwd: String, context: Context) 
    val n = ObservableField<String>(name)
    val p = ObservableField<String>(pwd)
    var context: Context = context

    /**
     * 用户名改变回调的函数
     */
    fun onNameChanged(s: CharSequence) 
        n.set(s.toString())
    

    /**
     * 密码改变的回调函数
     */
    fun onPwdChanged(s: CharSequence, start: Int, before: Int, count: Int) 
        p.set(s.toString())
    

    fun login() 
        if (n.get().equals(BaseConstant.USER_NAME)
            && p.get().equals(BaseConstant.USER_PWD)
        ) 
            Toast.makeText(context, "账号密码正确", Toast.LENGTH_SHORT).show()
            val intent = Intent(context, MainActivity::class.java)
            context.startActivity(intent)
        
    

4. 创建布局文件

<?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>
        <!--需要的viewModel,通过mBinding.vm=mViewMode注入-->
        <variable
            name="model"
            type="com.hkt.navigationapp.model.LoginModel"/>

        <variable
            name="activity"
            type="androidx.fragment.app.FragmentActivity"/>

        <import type="android.view.View"/>
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/tv_cancel"
            style="@style/WrapWrap"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:layout_marginTop="20dp"
            android:layout_marginStart="20dp"
            android:textSize="@dimen/txt_big_size"
            android:drawableStart="@drawable/common_ic_back"
            android:paddingStart="10dp"
            android:paddingEnd="10dp"
            android:drawablePadding="10dp"
            android:text="Cancel"
            android:onClick="@()-> activity.onBackPressed()"
            android:textColor="@color/colorPrimary"/>

        <TextView
            android:id="@+id/tv_title"
            style="@style/WrapWrap.ConstraintCenter"
            app:layout_constraintHorizontal_bias="0.1"
            app:layout_constraintVertical_bias="0.1"
            android:text="Welcome back"
            android:textColor="@color/textPrimary"
            android:padding="20dp"
            android:textSize="28sp"
            android:textStyle="bold"
            tools:ignore="MissingConstraints"/>

        <EditText
            android:id="@+id/et_account"
            style="@style/CommonEditStyle"
            app:layout_constraintTop_toBottomOf="@+id/tv_title"
            app:layout_constraintBottom_toTopOf="@+id/et_pwd"
            app:layout_constraintVertical_chainStyle="packed"
            app:layout_constraintVertical_bias="0.3"
            android:hint="account"
            android:text="@model.n.get()"
            android:onTextChanged="@(text, start, before, count)->model.onNameChanged(text)"
            android:drawableStart="@drawable/common_ic_account"
            tools:ignore="MissingConstraints"/>

        <!-- TODO android:onTextChanged="@(text, start, before, count)->model.onNameChanged(text)"  -->

        <EditText
            android:id="@+id/et_pwd"
            style="@style/CommonEditStyle"
            app:layout_constraintTop_toBottomOf="@+id/et_account"
            app:layout_constraintBottom_toTopOf="@+id/btn_register"
            android:layout_marginTop="20dp"
            android:hint="password"
            android:drawableStart="@drawable/common_ic_pwd"
            android:inputType="textPassword"
            android:onClick="@() -> model.login()"
            android:text="@model.p.get()"
            android:onTextChanged="@model::onPwdChanged"
            tools:ignore="MissingConstraints,UnknownId,UnknownIdInLayout"/>


        <Button
            android:id="@+id/btn_login"
            style="@style/CommonButtonStyle"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.8"
            android:text="Sign in"
            android:enabled="@(model.p.get().isEmpty()||model.n.get().isEmpty()) ? false : true"
            app:layout_constraintBottom_toBottomOf="parent"
            tools:ignore="MissingConstraints"/>


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

引入 Data Binding 之后的布局文件的使用方式会和以前的布局使用方式有很大的不同:

  • layout
    用作布局的根节点,只能包裹一个 View 标签,且不能包裹 merge 标签。

  • data
    Data Binding 的数据,只能存在一个 data 标签。

  • variable
    data 中使用,数据的变量标签,type 属性指明变量的类,如 com.hkt.navigationapp.model.LoginModelname 属性指明变量的名字,方便布局中使用。

  • import
    data 中使用,需要使用静态方法和静态常量,如需要使用 View.Visble 属性的时候,则需导入 <import type="android.view.View"/>type 属性指明类的路径,如果两个 import 标签导入的类名相同,则可以使用 alias 属性声明别名,使用的时候直接使用别名即可。

  • include
    View 标签中使用,作用同普通布局中的 include 一样,需要使用 bind:<参数名> 传递参数

  1. 生成绑定类
override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? 
        // 1.Binding生成的方式一
        val binding: LoginFragmentBinding = DataBindingUtil.inflate(
            inflater
            , R.layout.login_fragment
            , container
            , false
        )

        onSubscribeUi(binding)
        
        val loginModel = LoginModel("","",context!!)
        binding.model = loginModel
        binding.activity = activity

        return binding.root
    

小结

以上是关于Android Jetpack 学习之旅--> Data Binding 的使用的主要内容,如果未能解决你的问题,请参考以下文章

Android Jetpack 学习之旅--> Data Binding 的使用

Android Jetpack学习之旅--> Navigation 的使用

Android Jetpack 学习之旅--> ViewModel & LiveData 的使用

Android Jetpack 学习之旅--> Room 的使用

Lifecycle原理分析 ——《Android打怪升级之旅》

03Lifecycle源码分析 ——《Android打怪升级之旅》