[Android Jetpack series] 2. The use of DataBinding

foreword

This article, as the second part of learning Jetpack, will dataBindingintroduce and learn.

This article will explain dataBindingthe use of in detail, and highlight some pitfalls.

The development environment and SDK version used in this article are as follows, and readers should use a development environment no lower than that used in this article.

Android Studio 4.0.1
minSdkVersion 21
targetSdkVersion 30

turn ondataBinding

I believe you are still impressed with the opening method of viewBinding in the previous article .

The opening of dataBindingis exactly the same as before, we find again appin the modulebuild.gradle

build.gradle

Add the above code and sync, then startdataBinding

text

dataBindingThe writing format in the mode xml, if used 数据绑定, the corresponding layoutwriting needs to be in the specific format of the following style.

<?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">

    <!-- 数据模型 -->
    <data>
        ...
    </data>

    <!-- UI 布局 -->
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        ...

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

As mentioned above, the original UI layout needs to layoutbe wrapped by a label node, and everything xmlnsis written under the label.

Basic use of dataBinding

<data>...</data>What is the tag for? What is the data model?

First, create a beanclass or a entityclass to act as the data model, called here User.

data class User(
    var name: String,  //用户名
    var age: Int,  //年龄
    var member: Boolean  //团员否
)

layoutThe next step is to rewrite the above as follows:

<?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">

    <!-- 数据模型 -->
    <data>
        <variable name="user" type="com.example.databinding.bean.User" />
    </data>

    <!-- UI 布局 -->
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/userName"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.name}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />


        <TextView
            android:id="@+id/userAge"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{Integer.toString(user.age)}"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/userName" />

        <CheckBox
            android:id="@+id/userMember"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:checked="@{user.member}"
            android:text="团员否"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/userAge" />

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

It doesn't matter if you don't understand, just type it down first, and explain it bit by bit.

Can variables be written in layout?

See <data>...</data>what's under the tags first.

    ...
    <!-- 数据模型 -->
    <data>
        <variable name="user" type="com.example.databinding.bean.User" />
    </data>
    ...

variableLiteral translation is 变量the meaning, for here name="user"it means 变量名yes user, and the latter type="com.example.databinding.bean.User"means that userthe type of the variable is Usera class.

However, it is worth noting that it typeneeds to be written 全类名(ie: package name. class name).

How to use variables in layout?

So far, the variable user is bound to the layout.

Next is userhow variables layoutare used in:

Let's continue to look at the things below the UI layout.

    ...
    <!-- UI 布局 -->
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/userName"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.name}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />


        <TextView
            android:id="@+id/userAge"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{Integer.toString(user.age)}"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/userName" />

        <CheckBox
            android:id="@+id/userMember"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:checked="@{user.member}"
            android:text="团员否"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/userAge" />

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

It can be found that there is something like: in the above code @{user.name}``@{Integer.toString(user.age)} @{user.member}, I believe you already know what this is for.

@{...}The ellipsis 布局表达式can be replaced with any simple expression, here are a few simple examples:

    android:visibility="@{user.age > 13 ? View.GONE : View.VISIBLE}"

    android:text="@{user.age >= 18 ? `成年` : `未成年`}"

It should be noted that @{}only simple expressions are supported (you can try to write more yourself), and the following operations are not supported:

  • this
  • super
  • new
  • The generic call shown

Setting of variables in layout

layoutThe layout variables that have been defined above have been usersuccessfully defined, and @{}the variables have been used. Although the variables are successfully defined and used, where do the values ​​​​of the variables come from?

class MainActivity : AppCompatActivity() {
    
    
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
    
    
        super.onCreate(savedInstanceState)
        // 通过DataBindingUtil来设置layout布局
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        //为user变量设置值
        binding.user = User("张三", 18, true)
    }

    override fun onDestroy() {
    
    
        super.onDestroy()
        binding.unbind()
    }
}

bindingThe correspondence here is that res/layout/activity_main,xmlthis is the content already mentioned in the previous article.

At this point, dataBindingthe basic use of the program is over, let's run it again to see the results.

running.gif

Event handling of dataBinding

Above we introduced how to bind the operation event by dataBindinggiving the corresponding binding variable.layout

    <!-- 数据模型 -->
    <data>
        <variable name="user" type="com.example.databinding.bean.User" />
        <variable name="presenter" type="com.example.databinding.event.MainEventPresenter" />
    </data>

Now, <data>...</data>add an event variable to the tag, as the event action MainEventPresenterclass structure is as follows:

class MainEventPresenter {
    
    
    fun onClick(view: View) {
    
    
        Toast.makeText(view.context, "点击: $view", Toast.LENGTH_LONG).show()
    }

    fun testClick(view: View, user: User) {
    
    
        Toast.makeText(view.context, "点击: ${
      
      user.name}", Toast.LENGTH_LONG).show()
    }
}

Then add aButton

    <!-- UI 布局 -->
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        ...

        <Button
            android:id="@+id/presenterBtn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="@{presenter::onClick}"
            android:text="按钮"
            app:layout_constraintBottom_toBottomOf="userMember"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@id/userMember" />

    </androidx.constraintlayout.widget.ConstraintLayout>

Then set the variable value MainActivityin thepresenter

    ...
    binding.user = User("张三", 18, true)
    binding.presenter = MainEventPresenter()
    ...

Or you can write

    ...
    binding.apply {
    
    
        user = User("张三", 18, true)
        presenter = MainEventPresenter()
    }
    ...

Run it again and see the result.

running.gif

It is worth noting that: there are no brackets @{presenter::onClick}inonClick

dataBinding event handling and lambda anonymous function

The above is dataBindingthe binding method of the event, then there is one more point...

We said earlier @{}that it supports simple expressions, and there kotlinis another lambdaway of writing in , so we can try:

    android:onClick="@{(view)-> presenter.testClick(view)}"
    android:onClick="@{(view)-> presenter.testClick(view, user)}"

At this point, dataBindingthe basic use of event processing is over.

Use include in dataBinding

In Androiddevelopment, include -> layoutit is often done. Generally speaking, includethe imported layouts are part of the main layout (hereinafter referred to as sub-layouts).

dataBinding takes this into consideration, so it provides a special one bind:子布局变量名="被传递的变量名"to pass existing variables directly into sub-layouts.

Let's write a child layoutres/layout/layout_part1_main.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <variable name="user" type="com.example.databinding.bean.User" />
    </data>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:text="@{`include: ` + user.name}" />

    </RelativeLayout>
</layout>

Then import it in the main layout:

<?xml version="1.0" encoding="utf-8"?>
<layout ...
    xmlns:bind="http://schemas.android.com/tools">

    ...

    <!-- UI 布局 -->
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        ...

        <include
            layout="@layout/layout_part1_main"
            bind:user="@{user}" />

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

Note xmlns:bind="http://schemas.android.com/tools"that must be added.

Then let's run it again and see the results.

running.gif

The include layout here is displayed at the top, but the result is still expected...

Use import in dataBinding

Speaking of importwhich should be no strangers, dataBinding provides for... tags

As mentioned earlier, dataBinding does not support new objects. The usage classes imported using tags are generally tool classes, and those that can be used directly are:

静态成员属性, 静态方法

For example:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    ...>

    <!-- 数据模型 -->
    <data>
        <import type="android.text.TextUtils" />
        ...
    </data>

    <!-- UI 布局 -->
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        ...

        <TextView
            android:id="@+id/testDate"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{TextUtils.getReverse(`Hello World!`, 0, `Hello World!`.length())}"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@id/presenterBtn" />

            ...

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

The function realized by the above expression is to reverse the string and see the result.

running.gif

The same name, you can use aliasthe specified alias.

example:

    <import type="com.example.databinding.view.View" alias="MView" />
    <import type="android.view.View" />

So far, dataBinding has come to an end temporarily, and we will continue to introduce and use it later Observable.

The source code has been packaged to github and you can download it to view and run it yourself.

Guess you like

Origin blog.csdn.net/AoXue2017/article/details/126109056