Vincular exibições de layout a componentes de arquitetura

A biblioteca do AndroidX inclui os componentes de arquitetura, que podem ser usados para criar apps robustos, testáveis e de fácil manutenção. A Data Binding Library funciona perfeitamente com os componentes da arquitetura para simplificar ainda mais o desenvolvimento da sua IU. Os layouts do seu app podem se vincular aos dados dos componentes de arquitetura, que já ajudam a gerenciar o ciclo de vida dos controladores da IU e a notificar mudanças nos dados.

Esta página mostra como incorporar os componentes de arquitetura ao seu app para aumentar ainda mais os benefícios de usar a Data Binding Library.

Usar LiveData para notificar a IU sobre mudanças de dados

Você pode usar objetos LiveData como a fonte de vinculação de dados para notificar automaticamente a IU sobre mudanças nos dados. Para ver mais informações sobre esse componente de arquitetura, consulte Visão geral do LiveData.

Diferentemente dos objetos que implementam Observable, como os campos observáveis, os objetos LiveData conhecem o ciclo de vida dos observadores inscritos nas mudanças de dados. Esse conhecimento proporciona muitos benefícios, que são explicados em As vantagens de usar o LiveData. No Android Studio 3.1 e versões mais recentes, é possível substituir os campos observáveis por objetos LiveData no código de vinculação de dados.

Para usar um objeto LiveData com sua classe de vinculação, é preciso especificar um proprietário do ciclo de vida para definir o escopo do objeto LiveData. O exemplo a seguir especifica a atividade como a proprietária do ciclo de vida após a classe de vinculação ser instanciada:

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);
        }
    }
    

É possível usar o componente ViewModell, como explicado na seção Usar o ViewModel para gerenciar dados relacionados à IU, para vincular os dados ao layout. No componente ViewModel, é possível usar o objeto LiveData para transformar os dados ou combinar várias fontes de dados. O exemplo a seguir mostra como transformar os dados no 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);
        }
    }
    

Usar o ViewModel para gerenciar dados relacionados à IU

A Data Binding Library funciona perfeitamente com os componentes ViewModel, que expõem os dados que o layout observa e reagem às mudanças. O uso de componentes ViewModel com a Data Binding Library permite que você transfira a lógica da IU dos layouts para os componentes, que são mais fáceis de testar. A Data Binding Library garante que as visualizações sejam vinculadas e desvinculadas da fonte de dados quando necessário. O que resta a fazer é basicamente garantir que você está expondo os dados corretos. Para ver mais informações sobre esse componente de arquitetura, consulte Visão geral do ViewModel.

Para usar o componente ViewModel com a Data Binding Library, é necessário instanciar seu componente, que herda da classe ViewModel, conseguir uma instância da sua classe de vinculação e atribuir o componente ViewModel a uma propriedade da classe de vinculação. O exemplo a seguir mostra como usar o componente com a biblioteca:

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;
        }
    }
    

No layout, atribua as propriedades e os métodos do componente ViewModel às visualizações correspondentes usando expressões de vinculação, como mostrado no exemplo a seguir:

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

Usar um ViewModel observável para ter mais controle sobre os adaptadores de vinculação

Você pode usar um componente ViewModel que implementa Observable para notificar outros componentes do app sobre mudanças nos dados, da mesma forma que faria usando um objeto LiveData.

Há situações em que você pode preferir usar um componente ViewModel que implementa a interface Observable, em vez de usar objetos LiveData, mesmo que perca os recursos de gerenciamento do ciclo de vida do LiveData. Usar um componente ViewModel que implementa Observable oferece mais controle sobre os adaptadores de vinculação no seu app. Por exemplo, esse padrão oferece mais controle sobre as notificações quando há mudanças nos dados. Ele também permite que você especifique um método personalizado para definir o valor de um atributo na vinculação de dados bidirecional.

Para implementar um componente ViewModel observável, é necessário criar uma classe que seja herdada da classe ViewModel e implemente a interface Observable. É possível fornecer sua lógica personalizada quando um observador se inscrever ou cancelar a inscrição de notificações usando os métodos addOnPropertyChangedCallback() e removeOnPropertyChangedCallback(). Também é possível fornecer uma lógica personalizada que é executada quando as propriedades mudam no método notifyPropertyChanged(). O exemplo de código a seguir mostra como implementar um ViewModel observável:

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 should 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 should 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);
        }
    }
    

Outros recursos

Para saber mais sobre vinculação de dados, consulte os seguintes recursos adicionais.

Amostras

Codelabs

Postagens do blog