Работа с наблюдаемыми объектами данных

Наблюдаемость означает способность объекта уведомлять других об изменениях в его данных. Библиотека привязки данных позволяет сделать объекты, поля или коллекции наблюдаемыми.

Вы можете использовать любой объект для привязки данных, но изменение объекта не приводит к автоматическому обновлению пользовательского интерфейса. Вы можете использовать привязку данных, чтобы дать вашим объектам данных возможность уведомлять другие объекты (так называемые прослушиватели) при изменении их данных. Существует три типа наблюдаемых классов: поля , коллекции и объекты .

Когда один из этих наблюдаемых объектов данных привязан к пользовательскому интерфейсу и свойство объекта данных изменяется, пользовательский интерфейс обновляется автоматически.

Наблюдаемые поля

Если ваши классы имеют всего несколько свойств, возможно, не стоит создавать классы, реализующие интерфейс Observable . В этом случае вы можете использовать общий класс Observable и следующие классы, специфичные для примитивов, чтобы сделать поля наблюдаемыми:

Наблюдаемые поля — это автономные наблюдаемые объекты, имеющие одно поле. Примитивные версии избегают упаковки и распаковки во время операций доступа. Чтобы использовать этот механизм, создайте public final на языке программирования Java или свойство только для чтения в Kotlin, как показано в следующем примере:

class User {
   
val firstName = ObservableField<String>()
   
val lastName = ObservableField<String>()
   
val age = ObservableInt()
}
private static class User {
   
public final ObservableField<String> firstName = new ObservableField<>();
   
public final ObservableField<String> lastName = new ObservableField<>();
   
public final ObservableInt age = new ObservableInt();
}

Чтобы получить доступ к значению поля, используйте методы доступа set() и get() или используйте синтаксис свойств Kotlin :

user.firstName = "Google"
val age = user.age
user.firstName.set("Google");
int age = user.age.get();

Наблюдаемые коллекции

Некоторые приложения используют динамические структуры для хранения данных. Наблюдаемые коллекции позволяют получить доступ к этим структурам с помощью ключа. Класс ObservableArrayMap полезен, когда ключ имеет ссылочный тип, например String , как показано в следующем примере:

ObservableArrayMap<String, Any>().apply {
    put
("firstName", "Google")
    put
("lastName", "Inc.")
    put
("age", 17)
}
ObservableArrayMap<String, Object> user = new ObservableArrayMap<>();
user
.put("firstName", "Google");
user
.put("lastName", "Inc.");
user
.put("age", 17);

В макете вы можете найти карту с помощью строковых ключей, как показано в следующем примере:

<data>
   
<import type="android.databinding.ObservableMap"/>
   
<variable name="user" type="ObservableMap&lt;String, Object&gt;"/>
</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"/>

Класс ObservableArrayList полезен, когда ключ является целым числом, а именно:

ObservableArrayList<Any>().apply {
    add
("Google")
    add
("Inc.")
    add
(17)
}
ObservableArrayList<Object> user = new ObservableArrayList<>();
user
.add("Google");
user
.add("Inc.");
user
.add(17);

В макете доступ к списку можно получить через индексы, как показано в следующем примере:

<data>
   
<import type="android.databinding.ObservableList"/>
   
<import type="com.example.my.app.Fields"/>
   
<variable name="user" type="ObservableList&lt;Object&gt;"/>
</data>

<TextView
   
android:text='@{user[Fields.LAST_NAME]}'
   
android:layout_width="wrap_content"
   
android:layout_height="wrap_content"/>
<TextView
   
android:text='@{String.valueOf(1 + (Integer)user[Fields.AGE])}'
   
android:layout_width="wrap_content"
   
android:layout_height="wrap_content"/>

Наблюдаемые объекты

Класс, реализующий интерфейс Observable , позволяет регистрировать слушателей, которые хотят получать уведомления об изменениях свойств наблюдаемого объекта.

Интерфейс Observable имеет механизм добавления и удаления прослушивателей, но вы сами решаете, когда отправлять уведомления. Чтобы упростить разработку, библиотека привязки данных предоставляет класс BaseObservable , который реализует механизм регистрации прослушивателей. Класс данных, реализующий BaseObservable отвечает за уведомление об изменении свойств. Для этого назначьте аннотацию Bindable геттеру и вызовите метод notifyPropertyChanged() в установщике, как показано в следующем примере:

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)
       
}
}
private static class User extends BaseObservable {
   
private String firstName;
   
private String lastName;

   
@Bindable
   
public String getFirstName() {
       
return this.firstName;
   
}

   
@Bindable
   
public String getLastName() {
       
return this.lastName;
   
}

   
public void setFirstName(String firstName) {
       
this.firstName = firstName;
        notifyPropertyChanged
(BR.firstName);
   
}

   
public void setLastName(String lastName) {
       
this.lastName = lastName;
        notifyPropertyChanged
(BR.lastName);
   
}
}

Привязка данных создает в пакете модуля класс с именем BR , который содержит идентификаторы ресурсов, используемых для привязки данных. Аннотация Bindable создает запись в файле класса BR во время компиляции. Если базовый класс для классов данных не может быть изменен, вы можете реализовать интерфейс Observable , используя объект PropertyChangeRegistry для эффективной регистрации и уведомления прослушивателей.

Объекты с учетом жизненного цикла

Макеты в вашем приложении также можно привязывать к источникам привязки данных, которые автоматически уведомляют пользовательский интерфейс об изменениях в данных. Таким образом, ваши привязки учитывают жизненный цикл и запускаются только тогда, когда пользовательский интерфейс виден на экране.

Привязка данных поддерживает StateFlow и LiveData . Дополнительные сведения об использовании LiveData в привязке данных см. в разделе Использование LiveData для уведомления пользовательского интерфейса об изменениях данных .

Используйте StateFlow

Если ваше приложение использует Kotlin с сопрограммами , вы можете использовать объекты StateFlow в качестве источника привязки данных. Чтобы использовать объект StateFlow с классом привязки, укажите владельца жизненного цикла, чтобы определить область действия объекта StateFlow . В следующем примере действие указывается в качестве владельца жизненного цикла после создания экземпляра класса привязки:

class ViewModelActivity : AppCompatActivity() {
   
override fun onCreate(savedInstanceState: Bundle?) {
       
// Inflate view and obtain an instance of the binding class.
       
val binding: UserBinding = DataBindingUtil.setContentView(this, R.layout.user)

       
// Specify the current activity as the lifecycle owner.
        binding
.lifecycleOwner = this
   
}
}

Как описано в разделе «Привязка представлений макета к компонентам архитектуры» , привязка данных беспрепятственно работает с объектами ViewModel . Вы можете использовать StateFlow и ViewModel вместе следующим образом:

class ScheduleViewModel : ViewModel() {

   
private val _username = MutableStateFlow<String>("")
   
val username: StateFlow<String> = _username

   
init {
        viewModelScope
.launch {
           
_username.value = Repository.loadUserName()
       
}
   
}
}

В макете назначьте свойства и методы объекта ViewModel соответствующим представлениям с помощью выражений привязки, как показано в следующем примере:

<TextView
   
android:id="@+id/name"
   
android:text="@{viewmodel.username}" />

Пользовательский интерфейс автоматически обновляется при изменении значения имени пользователя.

Отключить поддержку StateFlow

Для приложений, использующих Kotlin и AndroidX, поддержка StateFlow автоматически включается в привязку данных. Это означает, что зависимость сопрограмм автоматически включается в ваше приложение, если зависимость еще не доступна.

Вы можете отказаться от этой функции, добавив в файл build.gradle следующее:

android {
   
...
    dataBinding
{
        addKtx
= false
   
}
}
android {
   
...
    dataBinding
{
        addKtx
= false
   
}
}

Альтернативно вы можете отключить StateFlow глобально в своем проекте, добавив следующую строку в файл gradle.properties :

android.defaults.databinding.addKtx = false
android.defaults.databinding.addKtx = false

Дополнительные ресурсы

Чтобы узнать больше о привязке данных, см. следующие дополнительные ресурсы:

Образцы

Кодлабы

Сообщения в блоге

{% дословно %}

Пока рекомендаций нет.

Попытайтесь в свой аккаунт Google.