Привязка представлений макетов к компонентам архитектуры

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

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

Используйте LiveData, чтобы уведомлять интерфейс об изменениях данных

Объекты LiveData можно использовать в качестве источника привязки данных, чтобы автоматически уведомлять интерфейс об изменениях в данных. Подробнее об этом компоненте архитектуры…

В отличие от объектов, реализующих Observable, например наблюдаемых полей, объекты LiveData знают о жизненном цикле наблюдателей, подписанных на изменения данных. Это дает множество преимуществ, которые описаны в разделе Преимущества использования LiveData. В Android Studio версии 3.1 и выше вы можете заменить наблюдаемые поля объектами LiveData в коде привязки данных.

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

Kotlin

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.setLifecycleOwner(this)
    }
}

Java

class ViewModelActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // Inflate view and obtain an instance of the binding class.
        UserBinding binding = DataBindingUtil.setContentView(this, R.layout.user);

        // Specify the current activity as the lifecycle owner.
        binding.setLifecycleOwner(this);
    }
}

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

Kotlin

class ScheduleViewModel : ViewModel() {
    val userName: LiveData

    init {
        val result = Repository.userName
        userName = Transformations.map(result) { result -> result.value }
    }
}

Java

class ScheduleViewModel extends ViewModel {
    LiveData username;

    public ScheduleViewModel() {
        String result = Repository.userName;
        userName = Transformations.map(result, result -> result.value);
    }
}

Используйте ViewModel для управления данными, связанными с пользовательским интерфейсом

Библиотека привязки данных без проблем работает с компонентами ViewModel. ViewModel предоставляет данные, которые отслеживает макет, и реагирует на их изменения. Использование компонентов ViewModel с библиотекой привязки данных позволяет перенести логику пользовательского интерфейса из макетов в компоненты, которые проще тестировать. Библиотека привязки данных гарантирует, что представления привязываются и отвязываются от источника данных по мере необходимости. Вам останется только убедиться, что вы предоставляете правильные данные. Подробнее об этом компоненте архитектуры можно узнать в обзоре ViewModel.

Чтобы использовать компонент ViewModel с библиотекой привязки данных, необходимо создать экземпляр компонента, который наследует от класса ViewModel, получить экземпляр класса привязки и назначить компонент ViewModel свойству в классе привязки. В примере ниже показано, как использовать компонент с библиотекой:

Kotlin

class ViewModelActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        // Obtain the ViewModel component.
        val userModel: UserModel by viewModels()

        // Inflate view and obtain an instance of the binding class.
        val binding: UserBinding = DataBindingUtil.setContentView(this, R.layout.user)

        // Assign the component to a property in the binding class.
        binding.viewmodel = userModel
    }
}

Java

class ViewModelActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // Obtain the ViewModel component.
        UserModel userModel = new ViewModelProvider(this).get(UserModel.class);

        // Inflate view and obtain an instance of the binding class.
        UserBinding binding = DataBindingUtil.setContentView(this, R.layout.user);

        // Assign the component to a property in the binding class.
        binding.viewmodel = userModel;
    }
}

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

<CheckBox
    android:id="@+id/rememberMeCheckBox"
    android:checked="@{viewmodel.rememberMe}"
    android:onCheckedChanged="@{() -> viewmodel.rememberMeChanged()}" />

Используйте Observable ViewModel для большего контроля над адаптерами привязки

Вы можете использовать компонент ViewModel, который реализует интерфейс Observable, чтобы уведомлять другие компоненты приложения об изменениях в данных, как и в случае с объектом LiveData.

В некоторых случаях лучше использовать компонент ViewModel, реализующий интерфейс Observable, а не объекты LiveData, даже если вы потеряете возможности управления жизненным циклом, которые предоставляет LiveData. Использование компонента ViewModel, реализующего Observable, дает вам больше контроля над адаптерами привязки в вашем приложении. Например, этот шаблон дает вам больше контроля над уведомлениями при изменении данных; он также позволяет указать собственный метод для установки значения атрибута в двусторонней привязке данных.

Чтобы реализовать наблюдаемый компонент ViewModel, создайте класс, наследующий от класса ViewModel и реализующий интерфейс Observable. Вы можете задать собственную логику для подписки наблюдателя на уведомления и отмены подписки с помощью методов addOnPropertyChangedCallback() и removeOnPropertyChangedCallback(). Вы также можете задать собственную логику, которая будет выполняться при изменении свойств в методе notifyPropertyChanged(). В следующем примере кода показано, как реализовать наблюдаемый объект ViewModel:

Kotlin

/**
 * A ViewModel that is also an Observable,
 * to be used with the Data Binding Library.
 */
open class ObservableViewModel : ViewModel(), Observable {
    private val callbacks: PropertyChangeRegistry = PropertyChangeRegistry()

    override fun addOnPropertyChangedCallback(
            callback: Observable.OnPropertyChangedCallback) {
        callbacks.add(callback)
    }

    override fun removeOnPropertyChangedCallback(
            callback: Observable.OnPropertyChangedCallback) {
        callbacks.remove(callback)
    }

    /**
     * Notifies observers that all properties of this instance have changed.
     */
    fun notifyChange() {
        callbacks.notifyCallbacks(this, 0, null)
    }

    /**
     * Notifies observers that a specific property has changed. The getter for the
     * property that changes must be marked with the @Bindable annotation to
     * generate a field in the BR class to be used as the fieldId parameter.
     *
     * @param fieldId The generated BR id for the Bindable field.
     */
    fun notifyPropertyChanged(fieldId: Int) {
        callbacks.notifyCallbacks(this, fieldId, null)
    }
}

Java

/**
 * A ViewModel that is also an Observable,
 * to be used with the Data Binding Library.
 */
class ObservableViewModel extends ViewModel implements Observable {
    private PropertyChangeRegistry callbacks = new PropertyChangeRegistry();

    @Override
    protected void addOnPropertyChangedCallback(
            Observable.OnPropertyChangedCallback callback) {
        callbacks.add(callback);
    }

    @Override
    protected void removeOnPropertyChangedCallback(
            Observable.OnPropertyChangedCallback callback) {
        callbacks.remove(callback);
    }

    /**
     * Notifies observers that all properties of this instance have changed.
     */
    void notifyChange() {
        callbacks.notifyCallbacks(this, 0, null);
    }

    /**
     * Notifies observers that a specific property has changed. The getter for the
     * property that changes must be marked with the @Bindable annotation to
     * generate a field in the BR class to be used as the fieldId parameter.
     *
     * @param fieldId The generated BR id for the Bindable field.
     */
    void notifyPropertyChanged(int fieldId) {
        callbacks.notifyCallbacks(this, fieldId, null);
    }
}

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

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