Android Data Binding Basic Sample
=============================================
This sample showcases the following features of the
[Data Binding library](https://developer.android.com/topic/libraries/data-binding/index.html):
* Layout variables and expressions
* Observability through Observable Fields, LiveData and Observable classes
* Binding Adapters, Binding Methods and Binding Converters
* Seamless integration with ViewModels
It shows common bad practices and their solutions in two different screens.
Features
--------
![Screenshot](https://github.com/googlesamples/android-databinding/blob/master/BasicSample/screenshots/screenshotbasic.png)
### Layout variables and expressions
With Data Binding you can write less boilerplate and repetitive code. It moves UI operations out
of the activities and fragments to the XML layout.
For example, instead of setting text on a TextView in an activity:
```java
TextView textView = findViewById(R.id.name);
textView.setText(user.name);
```
You assign the attribute to a variable, in the XML layout:
```xml
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.name}" />
```
See `ObservableFieldActivity.kt`, `ObservableFieldProfile.kt` and `observable_field_profile.xml`
for a simple example.
### Observability
In order to update the UI automatically when the data changes, Data Binding lets you bind attributes
with observable objects. You can choose between three mechanisms to achieve this: Observable fields,
LiveData and Observable classes.
#### Observable fields
Types like ObservableBoolean, ObservableInt and the generic ObservableField replace the
corresponding primitives to make them observable. Setting a new value on one of the Observable
fields will update the layout automatically.
```kotlin
class ProfileObservableFieldsViewModel : ViewModel() {
val likes = ObservableInt(0)
fun onLike() {
likes.increment() // Equivalent to set(likes.get() + 1)
}
}
```
In this example, when `onLike` is called, the number of likes is incremented
and the UI is updated. There is no need to notify that the property changed.
#### LiveData
LiveData is an observable from
[Android Architecture Components](https://developer.android.com/topic/libraries/architecture)
that is lifecycle-aware.
The advantages over Observable Fields are that LiveData supports
[Transformations](https://developer.android.com/reference/android/arch/lifecycle/Transformations)
and it's compatible with other components and libraries, like Room and WorkManager.
```kotlin
class ProfileLiveDataViewModel : ViewModel() {
private val _likes = MutableLiveData(0)
val likes: LiveData<Int> = _likes // Expose an immutable LiveData
fun onLike() {
_likes.value = (_likes.value ?: 0) + 1
}
}
```
It requires an extra step done on the binding:
```kotlin
binding.lifecycleOwner = this // use viewLifecycleOwner when assigning a fragment
```
#### Observable classes
For maximum flexibility and control, you can implement a fully observable class and decide when
to update certain properties. This lets you create dependencies between properties and it's
useful to dispatch partial UI updates, for example avoiding
potential glitches (UI elements updating almost at the same time).
```kotlin
class ProfileObservableViewModel : ObservableViewModel() {
val likes = ObservableInt(0)
fun onLike() {
likes.increment()
notifyPropertyChanged(BR.popularity)
}
@Bindable
fun getPopularity(): Popularity {
return likes.get().let {
when {
it > 9 -> Popularity.STAR
it > 4 -> Popularity.POPULAR
else -> Popularity.NORMAL
}
}
}
}
```
In this example, when `onLike` is called, the number of likes is incremented and the
`popularity` property is notified of a potential change (`popularity` depends on `likes`).
`getPopularity` is called by the library, returning a possible new value.
See `ProfileObservableFieldsViewModel.kt` for a complete example.
#### Binding adapters
Binding adapters let you customize or create layout attributes. For example, you can create
an `app:progressTint` attribute for progress bars where you change the color of the
progress indicator depending on an external value.
```kotlin
@BindingAdapter("app:progressTint")
@JvmStatic fun tintPopularity(view: ProgressBar, popularity: Popularity) {
val color = getAssociatedColor(popularity, view.context)
view.progressTintList = ColorStateList.valueOf(color)
}
```
The binding is created in the XML layout with:
```xml
<ProgressBar
app:progressTint="@{viewmodel.popularity}" />
```
Using binding adapters lets you move UI calls from the activity to static methods, improving
encapsulation.
You can also use multiple attributes in a Binding Adapter, see `viewmodel_profile.xml` for a complete
example.
#### Binding methods and binding converters
Binding methods and binding converters let you reduce code if your binding adapters
are very simple. You can read about them in the
[official guide](https://developer.android.com/topic/libraries/data-binding/index.html#attribute_setters).
For example, if an attribute's value needs to be passed to a method in the class:
```kotlin
@BindingAdapter("app:srcCompat")
@JvmStatic fun srcCompat(view: ImageView, @DrawableRes drawableId: Int) {
view.setImageResource(drawable)
}
```
You can replace this with a Binding Method which can be added to any class in the project:
```kotlin
@BindingMethods(
BindingMethod(type = ImageView::class,
attribute = "app:srcCompat",
method = "setImageDrawable"))
```
#### Binding Converters (use with caution)
In this sample we show a View depending on whether a number is zero. There are many options to do
this. We're showing two, one in the `observable_field_profile.xml`
and, the recommended way, in `viewmodel_profile.xml`.
The goal is to bind the view's visibility to the number of likes, but this won't work:
```xml
android:visibility="@{viewmodel.likes}" <!-- Doesn't work as expected -->
```
The number of likes is an integer and the visibility attribute takes an integer
(`VISIBLE`, `GONE` and `INVISIBLE` are 0, 4 and 8 respectively), so doing this would build,
but the result would not be the expected.
A possible solution is:
```xml
android:visibility="@{viewmodel.likes == 0 ? View.GONE : View.VISIBLE}"/
```
But it adds a relatively complex expression to the layout.
Instead, you can create and import a utils class:
```xml
<data>
<import type="com.example.android.databinding.basicsample.util.ConverterUtil" />
...
</data>
```
and use it from the View like so:
```xml
android:visibility="@{ConverterUtil.isZero(viewmodel.likes)}" <!-- don't do this either -->
```
`isZero` returns a boolean and `visibility` takes an integer so in order to convert
from boolean we can also define a BindingConversion:
```kotlin
@BindingConversion
@JvmStatic fun booleanToVisibility(isVisible: Boolean): Int { // Risky! applies everywhere
return if (isVisible) View.VISIBLE else View.GONE
}
```
This conversion is unsafe because this binding conversion is not restricted to our case: it will
convert all booleans to visibility integers when the attribute takes an integer.
Solution: As with every BindingConversion and BindingMethod, you can replace it with a Binding
Adapter, which normally is much simpler:
```kotlin
@BindingAdapter("app:hideIfZero") // Recommended solution
@JvmStatic fun hideIfZero(view: View, number: Int) {
view.visibility = if (number == 0) View.GONE else View.VISIBLE
}
```
and as shown in in `viewmodel_profile.xml`:
```xml
app:hideIfZero="@{viewmodel.likes}"
```
This defines a new custom attribute `hideIfZero` that can't be used accidentally.
As a rule of thumb it's preferable
没有合适的资源?快使用搜索试试~ 我知道了~
温馨提示
以下是Android Architecture Components的优势: 1. 代码结构清晰 Android Architecture Components提供了一些架构组件,例如ViewModel、LiveData和Room等,可以帮助开发者更好地组织代码结构,将代码分解成易于维护和测试的单元。 2. 提高代码质量 Android Architecture Components提供了一些最佳实践,例如单一职责原则、依赖倒置原则和开闭原则等,可以帮助开发者编写高质量、可扩展和易于测试的代码。 3. 简化异步编程 Android Architecture Components中的LiveData和ViewModel等组件可以帮助开发者管理UI状态和异步任务,避免了手动处理生命周期和内存泄漏等问题,简化了异步编程。 4. 支持数据绑定 Android Architecture Components中的Data Binding库可以帮助开发者将数据绑定到UI控件上,以减少手动设置UI控件的代码量,提高开发效率。 5. 易于学习和使用
资源推荐
资源详情
资源评论
收起资源包目录
Andro使用Data Binding将数据绑定到UI控件再使用RxBindings处理UI事件,实现双向数据流和响应式编程 (103个子文件)
gradlew.bat 3KB
gradlew.bat 3KB
.gitignore 87B
.gitignore 87B
.gitignore 7B
.gitignore 7B
build.gradle 2KB
build.gradle 2KB
build.gradle 2KB
build.gradle 2KB
settings.gradle 636B
settings.gradle 636B
gradlew 8KB
gradlew 8KB
gradle-wrapper.jar 60KB
gradle-wrapper.jar 60KB
IntervalTimerViewModel.kt 13KB
BindingAdapters.kt 6KB
MainActivity.kt 5KB
AnimationBindingAdapters.kt 5KB
NumberOfSetsBindingAdapters.kt 5KB
BindingAdapters.kt 4KB
IntervalTimerViewModelTest.kt 4KB
BasicUsageTest.kt 3KB
ProfileObservableViewModel.kt 3KB
BasicUsageTest.kt 2KB
ObservableFieldActivity.kt 2KB
ViewModelActivity.kt 2KB
TimerWrapper.kt 2KB
ObservableViewModel.kt 2KB
ObservableViewModel.kt 2KB
MainActivity.kt 2KB
BindingConverters.kt 2KB
Converter.kt 2KB
BindingMethods.kt 1KB
ProfileObservableViewModelTest.kt 1KB
IntervalTimerViewModelFactory.kt 1KB
ObservableFieldProfile.kt 968B
LICENSE 11KB
LICENSE 11KB
README.md 10KB
README.md 9KB
README.md 3KB
CONTRIBUTING.md 2KB
CONTRIBUTING.md 2KB
screenshot2way.png 121KB
screenshotbasic.png 62KB
ic_launcher_round.png 15KB
ic_launcher_round.png 15KB
ic_launcher_round.png 10KB
ic_launcher_round.png 10KB
ic_launcher.png 9KB
ic_launcher.png 9KB
ic_launcher_round.png 7KB
ic_launcher_round.png 7KB
ic_launcher.png 6KB
ic_launcher.png 6KB
ic_launcher_round.png 5KB
ic_launcher_round.png 5KB
ic_launcher.png 4KB
ic_launcher.png 4KB
ic_launcher.png 3KB
ic_launcher.png 3KB
ic_launcher_round.png 3KB
ic_launcher_round.png 3KB
ic_launcher.png 2KB
ic_launcher.png 2KB
proguard-rules.pro 751B
proguard-rules.pro 751B
gradle.properties 1KB
gradle.properties 1KB
ci-gradle.properties 776B
gradle-wrapper.properties 200B
gradle-wrapper.properties 200B
checksum.sh 1KB
interval_timer.xml 13KB
observable_field_profile.xml 8KB
viewmodel_profile.xml 7KB
ic_launcher_background.xml 6KB
ic_launcher_background.xml 6KB
activity_main.xml 4KB
ic_launcher_foreground.xml 2KB
ic_launcher_foreground.xml 2KB
AndroidManifest.xml 2KB
strings.xml 2KB
AndroidManifest.xml 1KB
ic_whatshot_black_96dp.xml 1KB
strings.xml 1KB
colors.xml 1KB
styles.xml 992B
styles.xml 990B
ic_person_black_96dp.xml 980B
colors.xml 898B
ic_launcher.xml 879B
ic_launcher_round.xml 879B
ic_launcher.xml 879B
ic_launcher_round.xml 879B
tags.xml 862B
TwoWaySample.yaml 2KB
BasicSample.yaml 2KB
共 103 条
- 1
- 2
资源评论
全面解读
- 粉丝: 2375
- 资源: 4
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功