Associazione delle visualizzazioni di layout ai componenti dell'architettura

La libreria AndroidX include i componenti dell'architettura, che puoi utilizzare per progettare app solide, testabili e gestibili. La libreria Data Binding si integra perfettamente con i componenti dell'architettura per semplificare ulteriormente lo sviluppo della UI. I layout nella tua app possono essere associati ai dati nei componenti dell'architettura, aiutandoti a gestire il ciclo di vita del controller UI e a inviare notifiche all'interfaccia utente in caso di modifiche ai dati.

Questa pagina mostra come incorporare i componenti dell'architettura nell'app per ottenere il massimo dall'utilizzo della libreria di associazione dei dati.

Utilizzare LiveData per notificare all'interfaccia utente le modifiche ai dati

Puoi utilizzare gli oggetti LiveData come origine di associazione di dati per notificare automaticamente all'interfaccia utente le modifiche ai dati. Per ulteriori informazioni su questo componente dell'architettura, consulta la panoramica di LiveData.

A differenza degli oggetti che implementano Observable, come i campi osservabili,LiveData gli oggetti conoscono il ciclo di vita degli osservatori sottoscritti alle modifiche ai dati. Questa conoscenza comporta molti vantaggi, illustrati nell'articolo Vantaggi dell'utilizzo di LiveData. In Android Studio 3.1 e versioni successive, puoi sostituire i campi osservabili con oggetti LiveData nel codice di associazione di dati.

Per utilizzare un oggetto LiveData con la classe di associazione, devi specificare un proprietario del ciclo di vita per definire l'ambito dell'oggetto LiveData. L'esempio seguente specifica l'attività come proprietario del ciclo di vita dopo la creazione dell'istanza della classe di associazione:

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

Puoi utilizzare un componente ViewModel, come spiegato nella sezione seguente, per associare i dati al layout. Nel componente ViewModel, puoi utilizzare l'oggetto LiveData per trasformare i dati o unire più origini dati. L'esempio seguente mostra come trasformare i dati in 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);
    }
}

Utilizzo di ViewModel per gestire i dati relativi all'interfaccia utente

La libreria di associazione dei dati funziona perfettamente con i componenti di ViewModel. ViewModel espone i dati osservati dal layout e reagisce alle sue modifiche. L'utilizzo dei componenti ViewModel con la libreria di associazione dei dati consente di spostare la logica dell'interfaccia utente dai layout ai componenti, che sono più facili da testare. La libreria di associazione dei dati garantisce che le viste siano associate e non associate all'origine dati, quando necessario. La maggior parte del lavoro rimanente consiste nell'assicurarti di esporre i dati corretti. Per ulteriori informazioni su questo componente dell'architettura, consulta la panoramica di ViewModel.

Per utilizzare il componente ViewModel con la libreria di associazione dei dati, devi istanziare il componente, che eredita dalla classe ViewModel, ottenere un'istanza della classe di associazione e assegnare il componente ViewModel a una proprietà nella classe di associazione. L'esempio seguente mostra come utilizzare il componente con la libreria:

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

Nel layout, assegna le proprietà e i metodi del componente ViewModel alle viste corrispondenti utilizzando espressioni di associazione, come mostrato nell'esempio seguente:

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

Utilizza un ViewModel Observable per un maggiore controllo sugli adattatori di associazione

Puoi utilizzare un componente ViewModel che implementa l'interfaccia Observable per notificare ad altri componenti dell'app le modifiche ai dati, in modo simile a come useresti un oggetto LiveData.

In alcune situazioni potrebbe essere preferibile utilizzare un componente ViewModel che implementa l'interfaccia Observable anziché gli oggetti LiveData, anche se perdi le funzionalità di gestione del ciclo di vita di LiveData. L'utilizzo di un componente ViewModel che implementa Observable offre un maggiore controllo sugli adattatori di associazione nella app. Ad esempio, questo pattern offre un maggiore controllo sulle notifiche quando i dati cambiano. Consente inoltre di specificare un metodo personalizzato per impostare il valore di un attributo nell'associazione di dati bidirezionale.

Per implementare un componente ViewModel osservabile, devi creare una classe che eredita dalla classe ViewModel e implementi l'interfaccia Observable. Puoi fornire una logica personalizzata quando un osservatore si iscrive alle notifiche o annulla l'iscrizione alle notifiche utilizzando i metodi addOnPropertyChangedCallback() e removeOnPropertyChangedCallback(). Puoi anche fornire una logica personalizzata da eseguire quando le proprietà cambiano nel metodo notifyPropertyChanged(). Il seguente esempio di codice mostra come implementare un elemento ViewModel osservabile:

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

Risorse aggiuntive

Per scoprire di più sull'associazione di dati, consulta le seguenti risorse aggiuntive.