Bidirektionale Datenbindung

Mit der einseitigen Datenbindung können Sie einen Wert für ein Attribut festlegen Listener, der auf eine Änderung dieses Attributs reagiert:

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

Die bidirektionale Datenbindung bietet eine Abkürzung für diesen Prozess:

<CheckBox
    android:id="@+id/rememberMeCheckBox"
    android:checked="@={viewmodel.rememberMe}"
/>

Die @={}-Notation, die vor allem das Zeichen „=“ enthält signieren, empfängt Daten Änderungen an der Property vornehmen und gleichzeitig Nutzeraktualisierungen beobachten.

Um auf Änderungen in den zugrunde liegenden Daten zu reagieren, können Sie Ihr Layout Variable eine Implementierung von Observable, normalerweise BaseObservable und verwenden Sie einen @Bindable-Annotation, wie in das folgende Code-Snippet:

Kotlin

class LoginViewModel : BaseObservable {
    // val data = ...

    @Bindable
    fun getRememberMe(): Boolean {
        return data.rememberMe
    }

    fun setRememberMe(value: Boolean) {
        // Avoids infinite loops.
        if (data.rememberMe != value) {
            data.rememberMe = value

            // React to the change.
            saveData()

            // Notify observers of a new value.
            notifyPropertyChanged(BR.remember_me)
        }
    }
}

Java

public class LoginViewModel extends BaseObservable {
    // private Model data = ...

    @Bindable
    public Boolean getRememberMe() {
        return data.rememberMe;
    }

    public void setRememberMe(Boolean value) {
        // Avoids infinite loops.
        if (data.rememberMe != value) {
            data.rememberMe = value;

            // React to the change.
            saveData();

            // Notify observers of a new value.
            notifyPropertyChanged(BR.remember_me);
        }
    }
}

Da die Getter-Methode des bindbaren Attributs getRememberMe() heißt, verwendet die entsprechende Setter-Methode der Property automatisch den Namen setRememberMe().

Weitere Informationen zur Verwendung von BaseObservable und @Bindable finden Sie unter Arbeiten mit beobachtbare Datenobjekte.

Bidirektionale Datenbindung mithilfe benutzerdefinierter Attribute

Die Plattform bietet bidirektionale Datenbindungen für die gängigsten Zwei-Wege-Attribute und ändern Listener, die Sie als Teil Ihrer App. Wenn Sie die bidirektionale Datenbindung mit benutzerdefinierten müssen Sie mit den Attributen @InverseBindingAdapter und @InverseBindingMethod Anmerkungen.

Wenn Sie beispielsweise die bidirektionale Datenbindung für ein "time"-Attribut aktivieren möchten, Führen Sie in der benutzerdefinierten Ansicht MyView die folgenden Schritte aus:

  1. Annotieren Sie die Methode, die den Anfangswert festlegt und aktualisiert, wenn der Wert Änderungen mit @BindingAdapter:

    Kotlin

    @BindingAdapter("time")
    @JvmStatic fun setTime(view: MyView, newValue: Time) {
        // Important to break potential infinite loops.
        if (view.time != newValue) {
            view.time = newValue
        }
    }

    Java

    @BindingAdapter("time")
    public static void setTime(MyView view, Time newValue) {
        // Important to break potential infinite loops.
        if (view.time != newValue) {
            view.time = newValue;
        }
    }
  2. Annotation der Methode, die den Wert aus der Ansicht liest, @InverseBindingAdapter:

    Kotlin

    @InverseBindingAdapter("time")
    @JvmStatic fun getTime(view: MyView) : Time {
        return view.getTime()
    }

    Java

    @InverseBindingAdapter("time")
    public static Time getTime(MyView view) {
        return view.getTime();
    }

An diesem Punkt weiß die Datenbindung, was zu tun ist, wenn sich die Daten ändern (sie ruft die Methode annotiert mit @BindingAdapter) und was Sie aufrufen, wenn sich das Ansichtsattribut ändert (das Attribut InverseBindingListener). Er weiß jedoch nicht, wann oder wie sich das Attribut ändert.

Dazu müssen Sie einen Listener für die Ansicht festlegen. Das kann ein benutzerdefinierter Listener sein. die mit Ihrer benutzerdefinierten Ansicht verknüpft sind. Es kann sich aber auch um ein allgemeines Ereignis wie oder eine Textänderung. Der Methode die Annotation @BindingAdapter hinzufügen , der den Listener für Änderungen an der Eigenschaft festlegt:

Kotlin

@BindingAdapter("app:timeAttrChanged")
@JvmStatic fun setListeners(
        view: MyView,
        attrChange: InverseBindingListener
) {
    // Set a listener for click, focus, touch, etc.
}

Java

@BindingAdapter("app:timeAttrChanged")
public static void setListeners(
        MyView view, final InverseBindingListener attrChange) {
    // Set a listener for click, focus, touch, etc.
}

Der Listener enthält einen InverseBindingListener als Parameter. Sie verwenden die InverseBindingListener, um dem Datenbindungssystem mitzuteilen, dass das Attribut geändert. Das System kann dann die mit der Anmerkung annotierte Methode aufrufen. @InverseBindingAdapter usw.

In der Praxis enthält dieser Listener eine nicht triviale Logik, einschließlich Listener für die Einweg-Datenbindung. Ein Beispiel finden Sie im Adapter für das Textattribut Änderung, TextViewBindingAdapter

Nutzer mit Conversion

Wenn die an ein View-Objekt gebundene Variable muss formatiert, übersetzt oder irgendwie geändert werden, bevor sie angezeigt werden. können Sie auch ein Converter-Objekt verwenden.

Nehmen wir als Beispiel ein EditText-Objekt mit einem Datum:

<EditText
    android:id="@+id/birth_date"
    android:text="@={Converter.dateToString(viewmodel.birthDate)}"
/>

Das Attribut viewmodel.birthDate enthält einen Wert vom Typ Long. Daher muss mithilfe eines Konverters formatiert werden.

Da ein Zwei-Wege-Ausdruck verwendet wird, muss auch ein Inverse-Ausdruck Converter, um der Bibliothek mitzuteilen, wie der vom Nutzer bereitgestellte String wieder konvertiert werden soll zum unterstützenden Datentyp hinzu, in diesem Fall Long. Hierzu fügen Sie Die Annotation @InverseMethod zu einem der Konverter hinzufügen, wobei diese Annotation auf den Kehrwert verweist. Nutzer mit Conversion. Ein Beispiel für diese Konfiguration finden Sie im folgenden Code: snippet:

Kotlin

object Converter {
    @InverseMethod("stringToDate")
    @JvmStatic fun dateToString(
        view: EditText, oldValue: Long,
        value: Long
    ): String {
        // Converts long to String.
    }

    @JvmStatic fun stringToDate(
        view: EditText, oldValue: String,
        value: String
    ): Long {
        // Converts String to long.
    }
}

Java

public class Converter {
    @InverseMethod("stringToDate")
    public static String dateToString(EditText view, long oldValue,
            long value) {
        // Converts long to String.
    }

    public static long stringToDate(EditText view, String oldValue,
            String value) {
        // Converts String to long.
    }
}

Endlosschleifen mit bidirektionaler Datenbindung

Achten Sie darauf, bei der bidirektionalen Datenbindung keine Endlosschleifen einzuführen. Wann? ein Attribut ändert, wird die Methode mit @InverseBindingAdapter wird aufgerufen und der Wert wird der unterstützenden Property. Dadurch wird wiederum die annotierte Methode mit @BindingAdapter, was einen weiteren Aufruf der annotierten Methode auslösen würde mit @InverseBindingAdapter usw.

Aus diesem Grund ist es wichtig, mögliche Endlosschleifen durch Vergleich neue und alte Werte in den Methoden, die mit @BindingAdapter annotiert wurden.

Zweiwege-Attribute

Die Plattform bietet integrierte Unterstützung für die Zwei-Wege-Datenbindung, wenn Sie die Attribute in der folgenden Tabelle. Weitere Informationen dazu, wie die Plattform Informationen zu dieser Unterstützung finden Sie in den Implementierungen für die entsprechenden Bindungsadapter:

Klasse Attribut(e) Bindungsadapter
AdapterView android:selectedItemPosition
android:selection
AdapterViewBindingAdapter
CalendarView android:date CalendarViewBindingAdapter
CompoundButton android:checked CompoundButtonBindingAdapter
DatePicker android:year
android:month
android:day
DatePickerBindingAdapter
NumberPicker android:value NumberPickerBindingAdapter
RadioButton android:checkedButton RadioGroupBindingAdapter
RatingBar android:rating RatingBarBindingAdapter
SeekBar android:progress SeekBarBindingAdapter
TabHost android:currentTab TabHostBindingAdapter
TextView android:text TextViewBindingAdapter
TimePicker android:hour
android:minute
TimePickerBindingAdapter

Weitere Informationen

Weitere Informationen zur Datenbindung finden Sie hier: zusätzliche Ressourcen.

Produktproben

Codelabs

Blogposts