DataBinding

本文最后更新于:2022年12月17日 上午

DataBinding

image-20221105181749287

DataBinding是Google提供给我们的数据绑定的支持库,实现在页面组件中直接绑定应用程序的数据源。

使用DataBinding

示例App要实现的功能是,点击按钮Button,TextView的数字+1

  1. 项目中引入dataBinding

    // 在build.gradle文件添加
    android{
       ...
       dataBinding{
          enabled true
       }
       ...
    }
  2. 新建activity和对应的layout布局文件。包括一个Button和一个Text View。

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello World"
            android:textSize="34sp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.422" />
    
        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/button"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.71" />
    
    </androidx.constraintlayout.widget.ConstraintLayout>
  3. 布局文件格式转换(普通layout➡️databing对应的layout)
    光标在布局文件的根布局➡️按Alt + Enter➡️点击 Convert to data binding layout

    得到转换后的layout布局文件,内容如下:

    <?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:id="@+id/textView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Hello World"
                android:textSize="34sp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintVertical_bias="0.422" />
    
            <Button
                android:id="@+id/button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/button"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintVertical_bias="0.71" />
    
        </androidx.constraintlayout.widget.ConstraintLayout>
    </layout>

    观察到外层嵌套了layout标签,里面增加了data标签。

  4. 创建MyViewModel类

    class MyViewModel : ViewModel() {
        private val _number = MutableLiveData<Int>()
        val number: LiveData<Int>
            get() = _number
    
        init {
            _number.value = 0
        }
    
        fun add() {
            _number.value = _number.value?.plus(1)
        }
    }
  5. 这里有两种方式实现+1功能

    • 方式一:

      DataBinding会基于layout创建一个Binding class,这个类包含了布局属性(定义的变量)到相关视图的所有绑定,并且会为布局中的数据元素生成setter,生成的类的名称是基于layout的名称(驼峰命名,加上Binding后缀)。比如布局名是activity_main.xml,生成的类就是ActivityMainBinding。你能通过这个类去inflate布局和数据模型,也可以通过DataBindingUtil类。

      • MainActivity使用DataBindingUtils加载布局,这里使用了懒加载,即随用随加载。

        private val binding: ActivityMainBinding by lazy {
            DataBindingUtil.setContentView(
                this,
                R.layout.activity_main
            )
        }
      • inflate加载布局(此方法也能用于RecyclerView, ViewPager

        class MainActivity : AppCompatActivity() {
            private val myViewModel by lazy { ViewModelProvider(this)[MyViewModel::class.java] }
            private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }
        
            override fun onCreate(savedInstanceState: Bundle?) {
                super.onCreate(savedInstanceState)
                setContentView(binding.root)
                ...
            }
        }

      上述两种方法大家二选一,一般在Activity中我们都用第一种。

      如果在fragment中绑定布局

      class MasterFragment : Fragment() {
      
          override fun onCreateView(
              inflater: LayoutInflater, container: ViewGroup?,
              savedInstanceState: Bundle?
          ): View {
              val viewModel = ViewModelProvider(requireActivity())[MyViewModel::class.java]
              val binding = DataBindingUtil.inflate<FragmentMasterBinding>(
                  inflater,
                  R.layout.fragment_master,
                  container,
                  false
              )
              binding.data = viewModel
              binding.lifecycleOwner = requireActivity()
              return binding.root
      }

      然后在MainActivityonCreate方法添加Observe和按钮点击事件

        myViewModel.number.observe(this) {
        	binding.textView.text = it.toString()
        }
        binding.button.setOnClickListener {
        	myViewModel.add()
        }
        
      - **方式二:**
      
        反向绑定,把数据数据绑定和按钮点击事件放在布局文件中
      
        在layout的data中添加:
      
        ```xml
        <data>
            <variable
            	name="data"
            	type="com.yorick.databinding.MyViewModel" />
        </data>

      修改TextView的text属性:

      android:text="@{data.number.toString()}"

      Button增加onClick属性:

      android:onClick="@{()->data.add()}"

      Activity仅保留以下代码:

      class MainActivity : AppCompatActivity() {
          private val myViewModel by lazy { ViewModelProvider(this)[MyViewModel::class.java] }
          private val binding: ActivityMainBinding by lazy {
              DataBindingUtil.setContentView(
                  this,
                  R.layout.activity_main
              )
          }
          override fun onCreate(savedInstanceState: Bundle?) {
              super.onCreate(savedInstanceState)
              binding.data = myViewModel
              binding.lifecycleOwner = this
          }
      }

参考:


DataBinding
https://yorick-ryu.github.io/Android/AndroidDataBinding/
作者
Yorick
发布于
2022年11月5日
许可协议