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

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

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

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

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

Если ваши классы имеют всего несколько свойств, возможно, не стоит создавать классы, реализующие интерфейс 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

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

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

Образцы

Кодлабы

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

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