乐趣区

关于android:当你真的学会DataBinding后你会发现这玩意真香

前言

🏀DataBinding 只是一种工具,用来解决 View 和数据之间的绑定。

Data Binding,顾名思义:数据绑定,它能够将布局页面中的组件和利用中的数据进行绑定,反对单向绑定和双向绑定,单向绑定就是如果数据有变动就会驱动页面进行变动,双向绑定就是除了单向绑定之外还反对页面的变动驱动数据的变动,如果页面中有一个输入框,那么咱们就能够进行双向绑定,数据变动,它的显示内容就变了,咱们手动输出内容也能够扭转绑定它的数据。

🌟官网文档:https://developer.android.goo…

🌟官网 Demo 地址:https://github.com/googlecode…

本文代码地址

如何应用 DataBinding 呢?

1. 启用 DataBinding

援用官网文档:

Databinding 与 Android Gradle 插件捆绑在一起。您无需申明对此库的依赖项,但必须启用它。

留神:即便模块不间接应用数据绑定,也必须为依赖于应用数据绑定的库的所有模块启用数据绑定。

// 在 gradle 的 android 下退出,而后点击 sync
android {
    ...
    //android studio 4.0 以下
    dataBinding{ }
    //android studio4.1 当前
    buildFeatures {dataBinding true}
}

2. 生成 DataBinding 布局

在咱们的布局文件中,抉择根目录的 View,按下 Alt+ 回车键,点击 Convert to data binding layout,就能够转换为DataBinding 布局啦。


而后咱们的布局就会变成这样:

<?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 元素,外面有 data 元素。咱们将在 data 元素中申明这个布局中应用到的变量,以及变量的类型。

举个例子:

<data>
    <import type="com.example...."/>
    <variable
        name="color"
        type="java.lang.String" />
</data>
  • data: 在标签内进行变量申明和导入等
  • variable: 进行变量申明
  • import: 导入须要的类

3. 申明一个 User 实体类

class User() {
    var name = "Taxze"
    var age = 18
    fun testOnclick() {Log.d("onclick", "test")
    }
}

4. 在 xml 中应用

而后在 data 中申明变量,以及类名

<data>
    <!-- <variable-->
    <!-- name="user"-->
    <!-- type="com.taxze.jetpack.databinding.User" />-->
    <import type="com.taxze.jetpack.databinding.User" />
​
    <variable
        name="user"
        type="User" />
</data>

而后在布局中应用 @{} 语法

// 伪代码,请勿间接 CV
<TextView
    ...
    android:text="@{user.name}"
/>

5. 在 Activity 或 Fragment 中应用 DataBinding

在 Activity 中通过 DataBindingUtil 设置布局文件,同时省略 Activity 的 setContentView 办法

class MainActivity : AppCompatActivity() {
    private lateinit var mainBinding: ActivityMainBinding
    private lateinit var mainUser: User
    override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)
        mainBinding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
        mainUser = User()
        mainBinding.user = mainUser
    }
}

在 Fragment 中应用:

class BlankFragment : Fragment() {
    private lateinit var mainFragmentBinding:FragmentBlankBinding
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {mainFragmentBinding = DataBindingUtil.inflate(inflater,R.layout.fragment_blank,container,false)
        return mainFragmentBinding.root
    }
}

零碎会为每个布局文件都生成一个绑定类。个别默认状况下,类的名称是布局文件名称转化为 Pascal 大小写模式,而后在开端增加 Binding 后缀,例如:名称为 activity_main 的布局文件,对应的类名就是ActivityMainBinding

运行之后的成果:

留神:只有当布局文件转换为 layout 款式之后,databinding才会依据布局文件的名字主动生成一个对应的 binding 类,你也能够在 build/generated/data_binding_base_source_out 目录下查看生成的类


最最最根底的应用就是这样,接下来咱们来讲讲如何更好的应用 DataBinding

如何在 xml 布局中更好的应用 DataBinding

1. 应用汇合中的元素

  • 退出咱们传入了一个汇合books,咱们能够通过以下形式应用:

    • 获取汇合的值
    • android:text="@{books.get(0).name}"
      android:text="@{books.[0].name}"
    • 增加默认值(⚡默认值无需加引号,且只在预览视图显示)
    • android:text="@{books.pages,default=330}"
    • 通过?? 或?: 来实现
    • android:text="@{books.pages != null ? book.pages : book.defaultPages}"
    • android:text="@{books.pages ?? book.defaultPages}"

2. 应用 map 中的数据

  • map类型的构造也能够通过 get 和 [] 两种形式获取

    • // 须要留神单双引号
      android:text="@{books.get('name')}"
    
    **3. 转换数据类型 **
  • 因为 DataBinding 不会主动做类型转换,所有咱们须要手动转换,例如在 text 标签内应用 String.valueOf()转换为 String 类型,在 rating 标签内咱们能够应用 Float.valueOf()进行转换

    • android:text="@{String.valueOf(book.pages)}"
    • android:rating="@{Float.valueOf(books.rating),default=2.0}"

    4. 导入包名抵触解决

  • 如果咱们导入的包名有抵触,咱们能够通过 alias 为它设置一个别名

    • // 伪代码,请勿间接 CV
      <data>
            <import type="com.xxx.a.Book" alias="aBook"/>
            <import type="com.xxx.B.Book" alias="bBook"/>
            ...

5. 隐式援用属性

  • 在一个 view 上援用其余 view 的属性

    • // 伪代码,请勿间接 CV
      <import type="android.view.View"/>
      ...
      <LinearLayout
          android:layout_width="match_parent"
          android:layout_height="match_parent">
          <CheckBox android:id="@+id/checkOne" .../>
          <ImageView android:visibility="@{checkOne.checked ? View.VISIBLE : View.GONE}" .../>
  • include标签和 ViewStub 标签

    • includemerge 标签的作用是实现布局文件的重用。就是说,为了高效复用及整合布局,使布局轻便化,咱们能够应用 includemerge标签将一个布局嵌入到另一个布局中,或者说将多个布局中的雷同元素抽取进去,独立治理,再复用到各个布局中,便于对立的调整。比方,一个利用中的多个页面都要用到对立款式的标题栏或底部导航栏,这时就能够将标题栏或底部导航栏的布局抽取进去,再以 include 标签模式嵌入到须要的布局中,而不是屡次 copy 代码,这样在批改时只需批改一处即可。而咱们同样能够通过 DataBinding 来进行数据绑定。
    • 例如:
    • //layout_title.xml
      <?xml version="1.0" encoding="utf-8"?>
      <layout xmlns:android="http://schemas.android.com/apk/res/android">
          <data>
              <import type="com.xxx.User" />
              <variable
                  name="userInfo"
                  type="User" />
          </data>
          <android.support.constraint.ConstraintLayout
              ...
              >
              <TextView
                  ...
                  android:text="@{userInfo.name}" />
          </android.support.constraint.ConstraintLayout>
      </layout>
    • 应用该布局,并传值
    • <include
          layout="@layout/layout_title"
          bind:test="@{userInfo}"/>
    • ViewStub 也是相似的用法,这里就不说了。
    • DataBinding 不反对 merge 标签

    6. 绑定点击事件

  • // 伪代码,请勿间接 CV
    onclick="@{()->user.testOnclick}"
    onclick="@{(v)->user.testOnclick(v)}"
    onclick="@{()->user.testOnclick(context)}"
    onclick="@{BindHelp::staticClick}"
    onclick="@{callback}"
    ​
    // 例如:<Button
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:onClick="@{()->user.testOnclick}"
        />

💡文章到这里讲的都是 DataBinding 如何设置数据,以及通过 DataBinding 在 xml 中的一些根底应用。如果只是应用 DataBinding 这个性能,那就有点大材小用了。它还有一个很弱小的性能咱们还没有讲,那就是数据更新时主动刷新 UI。

实现数据变动时自动更新 UI

一个一般的实体类或者 ViewModel 被更新后,并不会让 UI 自动更新。而咱们心愿,当数据变更后 UI 要自动更新,那么要实现数据变动时自动更新 UI,有三种办法能够应用,别离是BaseObservableObservableFieldObservableCollection

💡单向数据绑定:

  • BaseObservable

    BaseObservable 提供了两个刷新 UI 的办法,别离是 notifyPropertyChanged() 和 notifyChange()。

    • 第一步:批改实体类

      将咱们的实体类继承与 BaseObservable。须要响应变动的字段,就在对应变量的 get 函数上加 @Bindable。而后 set 中 notifyChange 是 kotlin 的写法,免去了 java 的 getter setter 的形式。成员属性须要响应变动的,就在其 set 函数中,notify 一下属性变动,那么 set 的时候,databinding 就会感知到。

      import androidx.databinding.BaseObservable
      import androidx.databinding.Bindable
      import androidx.databinding.library.baseAdapters.BR
      ​
      class User() : BaseObservable() {constructor(name: String, age: Int) : this() {
              this.name = name
              this.age = age
          }
          // 这是独自在 set 上 @bindable,name 能够为申明 private
          var name: String = ""
              set(value) {
                  field = value
                  notifyPropertyChanged(BR.name)
              }
              @Bindable
              get() = field
      ​
          // 这是在整个变量上申明 @bindable,所以必须是 public 的
          @Bindable
          var age:Int = 18
              set(value) {
                  field = value
                  notifyPropertyChanged(BR.age)
              }
              get() = field}
    • 第二步:在 Activity 中应用

      class MainActivity : AppCompatActivity() {
          private val TAG = "MainActivity"
          private lateinit var mainBinding: ActivityMainBinding
          private lateinit var mainUser: User
          override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)
              mainBinding =
                  DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
              mainUser = User("Taxze", 18)
              mainUser.addOnPropertyChangedCallback(object : Observable.OnPropertyChangedCallback() {override fun onPropertyChanged(sender: Observable, propertyId: Int) {
                      when {
                          BR.user == propertyId -> {Log.d(TAG, "BR.user")
                          }
                          BR.age == propertyId -> {Log.d(TAG, "BR.age")
                          }
                      }
                  }
              })
              mainBinding.user = mainUser
              mainBinding.onClickPresenter = OnClickPresenter()}
      ​
          inner class OnClickPresenter {fun changeName() {mainUser.name = "Taxze2222222"}
          }
      }
    • 须要留神的点

      • 官方网站只是提醒了开启 DataBinding 只须要在 build.gradle 中退出上面这行代码
      • buildFeatures {dataBinding true}

        然而,如果你想更好的应用 DataBinding 这是不够的,你还须要增加这些配置:

      • compileOptions {
            sourceCompatibility JavaVersion.VERSION_1_8
            targetCompatibility JavaVersion.VERSION_1_8
        }
        kotlinOptions {jvmTarget = '1.8'}
      • 🔥重点:在应用 DataBinding 得时候,BR对象,发现调用不了,生成也会报错,运行,须要在咱们 build.gradle 中进行一下配置:

        apply plugin: 'kotlin-kapt'
        kapt {generateStubs = true}

        而后从新运行一遍代码,你就会发现,BR文件主动生成啦!

  • ObservableField

    解说了 BaseObservable 后,当初来将建最简略也是最罕用的。只须要将实体类变动成这样即可:

    // 留神 observable 的属性须要 public 权限,否则 dataBinding 则无奈通过反射解决数据响应
    class User() : BaseObservable() {var name: ObservableField<String> = ObservableField("Taxze")
        var age:ObservableInt = ObservableInt(18)
    }
  • ObservableCollection

    dataBinding 也提供了包装类用于代替原生的 List 和 Map,别离是 ObservableList 和 ObservableMap

    实体类批改:

    // 伪代码,请勿间接 cv
    class User(){var userMap = ObservableArrayMap<String,String>()
    }
    // 应用时:mainUser.userMap["name"] = "Taxze"
    mainUser.userMap["age"] = "18"

    应用 ObservableCollection 后,xml与下面的略有不同,次要是数据的获取,须要指定 Key

    // 伪代码,请勿间接 cv
    ...
    <import type="android.databinding.ObservableMap" />
    <variable
             name="userMap"
             type="ObservableMap<String, String>" />
    ​
    // 应用时:<TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:hint="Name"
            android:text="@{userMap[`userName`]}" />

💡双向数据绑定:

  • 只须要在之前的单向绑定的根底上,将布局文件 @{} 变为@={},用于针对属性的数据扭转的同时监听用户的更新

DataBinding 在 RecyclerView 中的应用

在 RecyclerView 中应用 DataBinding 稍有变动,咱们在 ViewHolder 中进行 binding 对象的产生,以及数据对象的绑定。

咱们通过一个非常简单的例子来解说如何在 RecyclerView 中应用 DataBinding。

效果图:

  • 第一步:创立实体类

    就是咱们之前的,应用了 BaseObservable 的那个实体类,这里就不放代码了

  • 第二步:创立 activity_main 用于寄存 recyclerview

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/activty_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    ​
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            />
    ​
    </RelativeLayout>
  • 第三步:创立 text_item.xml 用于展现 recyclerview 中的每一行数据

    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:tools="http://schemas.android.com/tools"
        xmlns:android="http://schemas.android.com/apk/res/android">
    ​
        <data>
            <import type="com.taxze.jetpack.databinding.User" />
            <variable
                name="user"
                type="User" />
        </data>
    ​
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
    ​
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="40dp"
                android:background="#ffffff"
                android:orientation="horizontal"
                android:paddingStart="10dp">
    ​
                <TextView
                    android:id="@+id/tv_name"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center_vertical"
                    android:text="@{` 这个人的姓名是 ` + user.name}" />
    ​
                <TextView
                    android:id="@+id/tv_age"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center_vertical"
                    android:layout_marginLeft="20dp"
                    android:text="@{String.valueOf(user.age)}" />
            </LinearLayout>
        </LinearLayout>
    </layout>
  • 第四步:创立 Adapter

    有了之前的根底之后,大家看上面这些代码应该很容易了,就不做过多解说啦

    import android.content.Context
    import android.view.LayoutInflater
    import android.view.ViewGroup
    import androidx.databinding.DataBindingUtil
    import androidx.recyclerview.widget.RecyclerView
    import com.taxze.jetpack.databinding.databinding.TextItemBinding
    ​
    class FirstAdapter(users: MutableList<User>, context: Context) :
        RecyclerView.Adapter<FirstAdapter.MyHolder>() {// 在构造函数中申明 binding 变量,这样 holder 能力援用到,如果不加 val/var,就援用不到,就须要在 class 的 {} 内写 get 函数
        class MyHolder(val binding: TextItemBinding) : RecyclerView.ViewHolder(binding.root)
    ​
        private var users: MutableList<User> = arrayListOf()
        private var context: Context
    ​
        init {
            this.users = users
            this.context = context
        }
    ​
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyHolder {val inflater = LayoutInflater.from(context)
            val binding: TextItemBinding =
                DataBindingUtil.inflate(inflater, R.layout.text_item, parent, false)
            return MyHolder(binding)
        }
    ​
        override fun onBindViewHolder(holder: MyHolder, position: Int) {
            //java 写法能够 setVariable
            holder.binding.user = users[position]
            holder.binding.executePendingBindings()}
        //kotlin 中,return 的形式,能够简写
        override fun getItemCount() = users.size}
  • 第五步:在 MainActivity 中应用

    import android.os.Bundle
    import android.view.View
    import androidx.appcompat.app.AppCompatActivity
    import androidx.recyclerview.widget.LinearLayoutManager
    import androidx.recyclerview.widget.RecyclerView
    ​
    class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            initView()}
        // 给 RecyclerView 设置数据
        private fun initView() {val recyclerView = findViewById<View>(R.id.recyclerView) as RecyclerView
            recyclerView.layoutManager = LinearLayoutManager(this)
            val users: MutableList<User> = ArrayList()
            for (i in 0..100) {val user = User()
                user.name = "Taxze"
                user.age = i
                users.add(user)
            }
            val adapter = FirstAdapter(users, this)
            recyclerView.adapter = adapter
        }
    }

这样就实现了在 RecyclerView 中应用 DataBinding 啦。

高级用法

第一个:用于 appCompatImageView 的自定义属性

// 伪代码,请勿间接 cv
/**
 * 用于 appCompatImageView 的自定义属性,bind:imgSrc,命名空间 bind: 能够省略,也就是写作 imgSrc 亦可。能够用于加载 url 的图片
 * 函数名也是随便,次要是 value 的申明,就是新加的属性名了,能够多个属性同用,并配置是否必须一起作用
 * 函数名随便,办法签名才重要,匹配对象控件,以及属性参数。* 这里还能够增加 old 参数,获取批改新参数 之前对应的值。* todo 加载网络图片,须要网络权限!!!
 */
@JvmStatic
@BindingAdapter(value = ["bind:imgSrc"], requireAll = false)
fun urlImageSrc(view: AppCompatImageView, /*old: String?, */url: String) {Glide.with(view)
        .load(url)
        .placeholder(R.drawable.img_banner)
        .centerInside()
        .into(view)
}

第二个:配合 swipeRefreshLayout 的刷新状态的感知

  • 第一步:单向的,数据变动,刷新 UI

    // 伪代码,请勿间接 cv
    @JvmStatic
    @BindingAdapter("sfl_refreshing", requireAll = false)
    fun setSwipeRefreshing(view: SwipeRefreshLayout, oldValue: Boolean, newValue: Boolean) {
        // 判断是否是新的值,防止陷入死循环
        if (oldValue != newValue)
            view.isRefreshing = newValue
    }
  • 第二步:ui 的状态,反向绑定给数据变动

    // 伪代码,请勿间接 cv
    @JvmStatic
    @BindingAdapter("sfl_refreshingAttrChanged", requireAll = false)
    fun setRefreshCallback(view: SwipeRefreshLayout, listener: InverseBindingListener?) {
        listener ?: return
        view.setOnRefreshListener {
            // 由 ui 层的刷新状态变动,反向告诉数据层的变动
            listener.onChange()}
    }
  • 第三步:反向绑定的实现

    // 伪代码,请勿间接 cv
    /**
     * 反向绑定的实现,将 UI 的变动,回调给 bindingListener,listener 就会 onChange,告诉数据变动
     * 留神这里的 attribute 和 event,是跟下面两步配合统一才无效
     */
    @JvmStatic
    @InverseBindingAdapter(attribute = "sfl_refreshing", event = "sfl_refreshingAttrChanged")
    fun isSwipeRefreshing(view: SwipeRefreshLayout): Boolean {return view.isRefreshing}

DataBinding 配合 ViewModel&LiveData 一起应用

我将通过一个简略的例子带大家学习他们如何一起应用,话不多说,先上效果图:

  • 第一步:创立 UserModel

    // 将其继承于 AndroidViewModel(AndroidViewModel 也是继承于 ViewModel 的,然而 ViewModel 自身没有方法取得 Context,AndroidViewModel 提供 Application 用作 Context,并专门提供 Application 单例)​
    //UserName 应用 MutableLiveData
    class UserModel(application: Application) : AndroidViewModel(application) {var UserName = MutableLiveData("")
    }

<!—->

  • 第二步:创立 activity_main 和对应的 MainActivity

    <?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>
            <variable
                name="loginModel"
                type="com.taxze.jetpack.databinding.model.UserModel" />
        </data>
    ​
        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    ​
            <LinearLayout
                android:id="@+id/linearLayout"
                style="@style/InputBoxStyle"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="17dp"
                android:layout_marginEnd="17dp"
                app:layout_constraintBottom_toTopOf="@+id/guideline2"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintHorizontal_bias="0.0"
                app:layout_constraintStart_toStartOf="parent"
                tools:ignore="MissingConstraints">
    ​
                <EditText
                    android:id="@+id/editText"
                    style="@style/EditTextStyle"
                    android:layout_width="match_parent"
                    android:layout_height="50dp"
                    android:hint="请输出账号"
                    android:text="@={loginModel.UserName}"
                    tools:ignore="MissingConstraints" />
            </LinearLayout>
    ​
            <TextView
                android:id="@+id/textView2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:text='@{" 您输出的账号名是:"+loginModel.UserName,default=123123123}'
                android:textSize="24sp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/button"
                tools:ignore="MissingConstraints" />
    ​
            <androidx.constraintlayout.widget.Guideline
                android:id="@+id/guideline2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:orientation="horizontal"
                app:layout_constraintGuide_percent="0.4" />
    ​
            <Button
                android:id="@+id/button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="32dp"
                android:background="@drawable/button_drawable"
                android:text="登录"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/linearLayout"
                tools:ignore="MissingConstraints" />
        </androidx.constraintlayout.widget.ConstraintLayout>
    ​
    </layout>

<!—->

  • 第三步:在 MainActivity 中绑定页面和绑定申明周期

    class MainActivity : AppCompatActivity() {
        lateinit var viewDataBinding: ActivityMainBinding
        lateinit var model: UserModel
        override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)
            // 绑定页面
            viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
            // 绑定生命周期
            viewDataBinding.lifecycleOwner = this
            model = ViewModelProvider.AndroidViewModelFactory.getInstance(this.application)
                .create(UserModel::class.java)
            viewDataBinding.loginModel = model
    ​
            ...
        }
    }

<!—->

  • 第四步:传值

    viewDataBinding.button.setOnClickListener {val intent = Intent(MainActivity@ this, SecondActivity::class.java)
                intent.putExtra("user", "${model.UserName.value}")
                startActivity(intent)
            }
  • 第五步:在另外一个 activity 中调用

    class SecondActivity : AppCompatActivity() {
        lateinit var viewDataBinding: ActivitySecondBinding
        lateinit var userName: String
        override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)
            // 绑定页面
            viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_second)
            // 绑定生命周期
            viewDataBinding.lifecycleOwner = this
    ​
            userName = intent.getStringExtra("user").toString()
    ​
            viewDataBinding.tvName.text = "登录的账号是:$userName"
        }
    }

帮你踩坑🍖:

  • TextViewtext 属性,须要留神 data 不能为 Number 类型
  • xml中字符不能为中文(检查一下你的输入法)
  • 反射属性、函数必须是public
  • observableField数据的时候,在某些场合须要初始化,否则会运行报错!
  • 应用 LiveData 作为 dataBinding 的时候,须要在 ui 中设置binding.lifecycleOwner

尾述

这篇文章曾经很具体的讲了 DataBinding 的大部分用法,不过在看完文章后,你仍需多多实际,置信你很快就能够把握 DataBinding 啦😺 有问题欢送在评论区留言探讨~

对于我

Hello,我是 Taxze,如果您感觉文章对您有价值,心愿您能给我的文章点个❤️,也欢送关注我的博客。

如果您感觉文章还差了那么点货色,也请通过 关注 督促我写出更好的文章——万一哪天我提高了呢?😝

根底系列:

2022 · 让我带你 Jetpack 架构组件从入门到精通 — Lifecycle

学会应用 LiveData 和 ViewModel,我置信会让你在写业务时变得轻松🌞

当你真的学会 DataBinding 后,你会发现“这玩意真香”! (本文🌟)

以下局部还在码字,连忙点个珍藏吧🔥

2022 · 让我带你 Jetpack 架构组件从入门到精通 — Navigation

2022 · 让我带你 Jetpack 架构组件从入门到精通 — Room

2022 · 让我带你 Jetpack 架构组件从入门到精通 — Paging3

2022 · 让我带你 Jetpack 架构组件从入门到精通 — WorkManager

2022 · 让我带你 Jetpack 架构组件从入门到精通 — ViewPager2

2022 · 让我带你 Jetpack 架构组件从入门到精通 — 登录注册页面实战(MVVM)

进阶系列:

协程 + Retrofit 网络申请状态封装

Room 缓存封装

…..

退出移动版