Directorio de artículos
I. Introducción
El uso de las expresiones registradas anteriormente DataBinding
, este artículo continúa registrando el uso de objetos observables.
En segundo lugar, el campo observable
Aquí está la introducción del sitio web oficial.
La observabilidad se refiere a la capacidad de un objeto para informar a otros objetos de cambios en sus datos. Con las bibliotecas de enlace de datos, puede hacer observables objetos, campos o colecciones.
Se puede usar cualquier objeto simple para el enlace de datos, pero la modificación del objeto no actualiza automáticamente la interfaz. Con el enlace de datos, los objetos de datos pueden notificar a otros objetos, u oyentes, cuando cambien sus datos. Hay tres tipos diferentes de clases observables: objetos , campos y colecciones .
Cuando uno de los objetos de datos observables está vinculado a la interfaz y las propiedades de ese objeto de datos cambian, la interfaz se actualiza automáticamente.
Aquí hay un ejemplo para ilustrar el papel de la observabilidad. Veamos primero el código que no usa campos observables. Aquí, las clases ordinarias se usan para el enlace de datos para mostrar contenido.
activity_main.xml
<?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:bind="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="change"
type="String" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/update_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="@{change}"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
tools:text="value" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
MainActivity.kt
class MainActivity : AppCompatActivity() {
private var changeValue = "你好啊"
private val binding: ActivityMainBinding by lazy {
ActivityMainBinding.inflate(layoutInflater)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
binding.change = changeValue
changeValue = "我不好"
}
}
El código primero xml
se vincula con la cadena sum y luego cambia la cadena más tarde. El resultado es de esperar, el contenido modificado más tarde no se mostrará en el diseño de la interfaz de usuario, lo cual es un fenómeno normal. Pero en el proyecto, suponiendo que este campo deba cambiarse muchas veces, binding.change = changeValue
será muy engorroso volver a ejecutarlo cada vez después de la asignación. Entonces, la función de campo observable se introduce aquí, veamos el código modificado a continuación.
activity_main.xml
<?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:bind="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="change"
type="androidx.databinding.ObservableField<String>" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/update_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="@{change}"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
tools:text="value" />
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/update_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="@{input.text}"
app:layout_constraintTop_toBottomOf="@+id/input"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
MainActivity.kt
class MainActivity : AppCompatActivity() {
private val changeValue = ObservableField<String>("你好啊")
private val binding: ActivityMainBinding by lazy {
ActivityMainBinding.inflate(layoutInflater)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
binding.change = changeValue
changeValue.set("我不好")
}
}
De esta manera, la interfaz de usuario se puede cambiar en tiempo real cuando se cambia el contenido de la cadena.
DataBinding
Los campos observables básicos proporcionados en son los siguientes
Hay algo de trabajo por hacer cuando se crea una clase que implementa la Observable
interfaz , pero no tiene mucho sentido si su clase tiene solo unas pocas propiedades. En este caso, puede usar la Observable
clase y las siguientes clases específicas de primitivas para hacer que el campo sea observable:
ObservableBoolean
ObservableByte
ObservableChar
ObservableShort
ObservableInt
ObservableLong
ObservableFloat
ObservableDouble
ObservableParcelable
Por ejemplo, si creamos una nueva clase para almacenar información del usuario, podemos completar las variables observables.
class User {
val firstName = ObservableField<String>()
val lastName = ObservableField<String>()
val age = ObservableInt()
}
3. Colección observable
Además de los campos observables, también hay colecciones observables, principalmente ObservableArrayMap
yObservableArrayList
ObservableArrayMap<String, Any>().apply {
put("firstName", "Google")
put("lastName", "Inc.")
put("age", 17)
}
ObservableArrayList<Any>().apply {
add("Google")
add("Inc.")
add(17)
}
<data>
<import type="android.databinding.ObservableMap"/>
<variable name="user" type="ObservableMap<String, Object>"/>
<import type="android.databinding.ObservableList"/>
<import type="com.example.my.app.Fields"/>
<variable name="user2" type="ObservableList<Object>"/>
</data>
…
<TextView
android:text="@{user.lastName}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:text="@{String.valueOf(1 + (Integer)user.age)}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:text='@{user2[Fields.LAST_NAME]}'
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:text='@{String.valueOf(1 + (Integer)user2[Fields.AGE])}'
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
4. Objetos observables
A veces, el método proporcionado oficialmente no puede satisfacer las necesidades y debe expandirse por sí mismo. En este momento, se puede implementar Observable
para completar esta función.
class User : BaseObservable() {
@get:Bindable
var firstName: String = ""
set(value) {
field = value
notifyPropertyChanged(BR.firstName)
}
@get:Bindable
var lastName: String = ""
set(value) {
field = value
notifyPropertyChanged(BR.lastName)
}
}
Lo siguiente se cita de la documentación oficial.
El enlace de datos genera
BR
una que contiene el ID del recurso utilizado para el enlace de datos. Durante la compilación,Bindable
las anotaciones generan una entrada en el archivo deBR
clase . Si la clase base de la clase de datos no se puede cambiar, laObservable
interfaz se puede implementar usando unPropertyChangeRegistry
objeto para registrar y notificar a los oyentes de manera efectiva.
Cómo implementar Observable
la interfaz
class User : Observable {
private val property : PropertyChangeRegistry by lazy {
//默认是线程安全的
PropertyChangeRegistry()
}
@get:Bindable
var change: String = ""
set(value) {
field = value
notifyPropertyChanged(BR.change)
}
override fun addOnPropertyChangedCallback(callback: Observable.OnPropertyChangedCallback?) {
property.add(callback)
}
override fun removeOnPropertyChangedCallback(callback: Observable.OnPropertyChangedCallback?) {
property.remove(callback)
}
fun notifyChange(){
property.notifyCallbacks(this, 0, null)
}
fun notifyPropertyChanged(fieldId : Int) {
property.notifyCallbacks(this, fieldId, null);
}
}