foreword
This article, as the second part of learning Jetpack, will dataBinding
introduce and learn.
This article will explain dataBinding
the 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 dataBinding
is exactly the same as before, we find again app
in the modulebuild.gradle
Add the above code and sync
, then startdataBinding
text
dataBinding
The writing format in the mode xml
, if used 数据绑定
, the corresponding layout
writing 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 layout
be wrapped by a label node, and everything xmlns
is written under the label.
Basic use of dataBinding
<data>...</data>
What is the tag for? What is the data model?
First, create a bean
class or a entity
class to act as the data model, called here User
.
data class User(
var name: String, //用户名
var age: Int, //年龄
var member: Boolean //团员否
)
layout
The 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>
...
variable
Literal translation is 变量
the meaning, for here name="user"
it means 变量名
yes user
, and the latter type="com.example.databinding.bean.User"
means that user
the type of the variable is User
a class.
However, it is worth noting that it type
needs 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 user
how variables layout
are 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
layout
The layout variables that have been defined above have been user
successfully 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()
}
}
binding
The correspondence here is that res/layout/activity_main,xml
this is the content already mentioned in the previous article.
At this point, dataBinding
the basic use of the program is over, let's run it again to see the results.
Event handling of dataBinding
Above we introduced how to bind the operation event by dataBinding
giving 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 MainEventPresenter
class 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 MainActivity
in 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.
It is worth noting that: there are no brackets
@{presenter::onClick}
inonClick
dataBinding event handling and lambda anonymous function
The above is dataBinding
the binding method of the event, then there is one more point...
We said earlier @{}
that it supports simple expressions, and there kotlin
is another lambda
way of writing in , so we can try:
android:onClick="@{(view)-> presenter.testClick(view)}"
或
android:onClick="@{(view)-> presenter.testClick(view, user)}"
At this point, dataBinding
the basic use of event processing is over.
Use include in dataBinding
In Android
development, include -> layout
it is often done. Generally speaking, include
the 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.
The include layout here is displayed at the top, but the result is still expected...
Use import in dataBinding
Speaking of import
which 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.
The same name, you can use alias
the 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.