Powiąż widoki układu z komponentami architektury

Biblioteka AndroidX zawiera komponenty architektury, których można używać do projektowania solidnych, sprawdzonych i łatwych w obsłudze aplikacji. Biblioteka powiązań danych płynnie współpracuje z komponentami architektury, co ułatwia tworzenie interfejsu użytkownika. Układy w aplikacji mogą tworzyć powiązania z danymi z komponentów architektury, co ułatwia zarządzanie cyklem życia kontrolera interfejsu i powiadamianie UI o zmianach w danych.

Na tej stronie pokazujemy, jak włączyć komponenty architektury do aplikacji, aby w pełni wykorzystać możliwości biblioteki powiązań danych.

Używaj LiveData do powiadamiania interfejsu użytkownika o zmianach danych

Obiekty LiveData mogą służyć jako źródło powiązania danych, aby automatycznie powiadamiać interfejs użytkownika o zmianach w danych. Więcej informacji o tym komponencie architektury znajdziesz w omówieniu LiveData.

W odróżnieniu od obiektów, które implementują Observable – takich jak pola obserwowalneLiveData – wiedzą o cyklu życia obserwatorów zasubskrybowanych zmian danych. Wiedza ta przynosi wiele korzyści, które zostały opisane w sekcji Zalety korzystania z LiveData. W Android Studio w wersji 3.1 lub nowszej możesz w kodzie wiązania danych zastąpić obserwowalne pola obiektami LiveData.

Aby użyć obiektu LiveData z klasą powiązania, musisz określić właściciela cyklu życia, który określi zakres obiektu LiveData. Ten przykład określa aktywność jako właściciela cyklu życia po utworzeniu wystąpienia klasy powiązania:

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

Aby powiązać dane z układem, możesz użyć komponentu ViewModel, jak wyjaśniliśmy w następnej sekcji. W komponencie ViewModel możesz używać obiektu LiveData do przekształcania danych lub scalania wielu źródeł danych. Ten przykład pokazuje, jak przekształcić dane w elemencie 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);
    }
}

Używaj obiektu ViewModel do zarządzania danymi związanymi z interfejsem użytkownika

Biblioteka powiązań danych płynnie współpracuje z komponentami ViewModel. Element ViewModel wyświetla dane, które obserwuje układ, i reaguje na jego zmiany. Użycie komponentów ViewModel z biblioteką powiązań danych pozwala przenieść logikę UI z układów na komponenty, które są łatwiejsze do przetestowania. Biblioteka powiązań danych gwarantuje, że w razie potrzeby widoki danych są powiązane ze źródłem danych i nie są usuwane. Większość pozostałych czynności musisz wykonać, aby zadbać o dostęp do właściwych danych. Więcej informacji o tym komponencie architektury znajdziesz w omówieniu ViewModel.

Aby użyć komponentu ViewModel z biblioteką wiązań danych, musisz go zainicjować – który dziedziczy z klasy ViewModel, uzyskać wystąpienie klasy powiązania i przypisać komponent ViewModel do właściwości w klasie powiązania. Poniższy przykład pokazuje, jak korzystać z komponentu z biblioteką:

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

W swoim układzie przypisz właściwości i metody komponentu ViewModel do odpowiednich widoków, korzystając z wyrażeń powiązania, jak w tym przykładzie:

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

Użyj obiektu ViewModel, aby uzyskać większą kontrolę nad adapterami wiązań

Aby powiadamiać inne komponenty aplikacji o zmianach w danych, możesz użyć komponentu ViewModel, który implementuje interfejs Observable, podobnie jak w przypadku obiektu LiveData.

W pewnych sytuacjach lepiej użyć komponentu ViewModel, który implementuje interfejs Observable, a nie obiektów LiveData, nawet jeśli utracisz możliwość zarządzania cyklem życia LiveData. Użycie komponentu ViewModel, który implementuje Observable, daje Ci większą kontrolę nad adapterami wiązań w aplikacji. Na przykład ten wzorzec zapewnia większą kontrolę nad powiadomieniami w przypadku zmiany danych; umożliwia też określenie niestandardowej metody ustawiania wartości atrybutu w dwukierunkowym wiązaniu danych.

Aby wdrożyć obserwowalny komponent ViewModel, musisz utworzyć klasę, która dziedziczy z klasy ViewModel, i implementuje interfejs Observable. Możesz zastosować niestandardowe mechanizmy logiczne, w przypadku których obserwator subskrybuje powiadomienia lub anuluje ich subskrypcję, korzystając z metod addOnPropertyChangedCallback() i removeOnPropertyChangedCallback(). Możesz też podać niestandardową logikę, która uruchamia się, gdy zmienią się właściwości w metodzie notifyPropertyChanged(). Ten przykładowy kod pokazuje, jak wdrożyć obserwowany element 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);
    }
}

Dodatkowe materiały

Więcej informacji o wiązaniu danych znajdziesz w tych dodatkowych materiałach.