写点什么

当你真的学会 DataBinding 后,你会发现“这玩意真香”!

  • 2022 年 7 月 01 日
  • 本文字数:13166 字

    阅读完需:约 43 分钟

当你真的学会DataBinding后,你会发现“这玩意真香”!

前言

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


Data Binding,顾名思义:数据绑定,它可以将布局页面中的组件和应用中的数据进行绑定,支持单向绑定和双向绑定,单向绑定就是如果数据有变化就会驱动页面进行变化,双向绑定就是除了单向绑定之外还支持页面的变化驱动数据的变化,如果页面中有一个输入框,那么我们就可以进行双向绑定,数据变化,它的显示内容就变了,我们手动输入内容也可以改变绑定它的数据。


🌟官方文档:https://developer.android.google.cn/jetpack/androidx/releases/databinding


🌟官方 Demo 地址:https://github.com/googlecodelabs/android-databinding


本文代码地址

如何使用 DataBinding 呢?

1.启用 DataBinding


引用官方文档:

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

注意:即使模块不直接使用数据绑定,也必须为依赖于使用数据绑定的库的所有模块启用数据绑定。


//在gradle的android下加入,然后点击syncandroid {    ...    //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,我们可以通过以下方式使用:

  • 获取集合的值


    -   添加默认值(⚡默认值无需加引号,且只在预览视图显示)    -   ```xml        android:text="@{books.pages,default=330}"
复制代码


-   通过??或?:来实现-   ```xml    android:text="@{books.pages != null ? book.pages : book.defaultPages}"
复制代码


    -   ```xml        android:text="@{books.pages ?? book.defaultPages}"
复制代码


2.使用 map 中的数据


  • map类型的结构也可以通过 get 和[]两种方式获取



**3.转换数据类型**
- 因为`DataBinding`不会自动做类型转换,所有我们需要手动转换,例如在text标签内使用String.valueOf()转换为String类型,在rating标签内我们可以使用Float.valueOf()进行转换
- ```xml android:text="@{String.valueOf(book.pages)}"
复制代码


-   ```xml    android:rating="@{Float.valueOf(books.rating),default=2.0}"
复制代码



**4.导入包名冲突处理**
- 如果我们导入的包名有冲突,我们可以通过`alias`为它设置一个别名
- ```xml //伪代码,请勿直接CV <data> <import type="com.xxx.a.Book" alias="aBook"/> <import type="com.xxx.B.Book" alias="bBook"/> ... </data>
复制代码


5.隐式引用属性


  • 在一个view上引用其他view的属性



- **`include`**标签和**`ViewStub`**标签
- `include`和`merge`标签的作用是实现布局文件的重用。就是说,为了高效复用及整合布局,使布局轻便化,我们可以使用`include`和`merge`标签将一个布局嵌入到另一个布局中,或者说将多个布局中的相同元素抽取出来,独立管理,再复用到各个布局中,便于统一的调整。 比如,一个应用中的多个页面都要用到统一样式的标题栏或底部导航栏,这时就可以将标题栏或底部导航栏的布局抽取出来,再以`include`标签形式嵌入到需要的布局中,而不是多次copy代码,这样在修改时只需修改一处即可。而我们同样可以通过`DataBinding`来进行数据绑定。 - 例如: - ```xml //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.绑定点击事件**
- ```xml //伪代码,请勿直接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 缓存封装


.....

发布于: 刚刚阅读数: 3
用户头像

他日若遂凌云志 敢笑黄巢不丈夫 2020.10.15 加入

曾许少年凌云志,誓做人间第一流. 一起加入Flutter技术交流群532403442 有好多好多滴学习资料喔~ 小T目前主攻Android与Flutter, 通常会搞搞人工智能、SpringBoot 、Mybatiys等.

评论

发布
暂无评论
当你真的学会DataBinding后,你会发现“这玩意真香”!_JetPack_编程的平行世界_InfoQ写作社区