Wygenerowane klasy powiązań

Biblioteka powiązań danych generuje klasy powiązań, których możesz używać do uzyskiwania dostępu do zmiennych i widoków układu. Ta dokumentacja pokazuje, jak tworzyć i dostosowywać wygenerowane klasy powiązania.

Wygenerowana klasa powiązania łączy zmienne układu z widokami w układzie. Możesz dostosować nazwę i pakiet wiązania. Wszystkie wygenerowane klasy powiązań dziedziczą po klasie ViewDataBinding.

Klasa powiązania jest generowana dla każdego pliku układu. Domyślnie nazwa klasy to nazwa pliku układu przekonwertowanego na wielkość liter w formacie Pascal z dodanym sufiksem Wiązanie. Jeśli na przykład nazwa pliku szablonu to activity_main.xml, odpowiadająca mu klasa to ActivityMainBinding. Ta klasa zawiera wszystkie powiązania właściwości układu z widokami układu i wie, jak przypisywać wartości wyrażeń powiązań.

Tworzenie obiektu powiązania

Obiekt powiązania jest tworzony natychmiast po uzupełnieniu układu, dzięki czemu hierarchia widoków nie zostanie zmodyfikowana, zanim nastąpi powiązanie z widokami z wyrażeniami w układzie. Najczęstszą metodą wiązania obiektu z układem jest użycie metod statycznych w klasie powiązania. Możesz powiększyć hierarchię widoków danych i powiązać z nią obiekt za pomocą metody inflate() klasy powiązania, jak pokazano w tym przykładzie:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    val binding: MyLayoutBinding = MyLayoutBinding.inflate(layoutInflater)

    setContentView(binding.root)
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    MyLayoutBinding binding = MyLayoutBinding.inflate(getLayoutInflater());

    setContentView(binding.root);
}

Istnieje alternatywna wersja metody inflate(), która oprócz obiektu LayoutInflater pobiera obiekt ViewGroup, jak pokazano w tym przykładzie:

Kotlin

val binding: MyLayoutBinding = MyLayoutBinding.inflate(getLayoutInflater(), viewGroup, false)

Java

MyLayoutBinding binding = MyLayoutBinding.inflate(getLayoutInflater(), viewGroup, false);

Jeśli szablon został przekroczony za pomocą innego mechanizmu, możesz powiązać go oddzielnie w ten sposób:

Kotlin

val binding: MyLayoutBinding = MyLayoutBinding.bind(viewRoot)

Java

MyLayoutBinding binding = MyLayoutBinding.bind(viewRoot);

Czasami typ wiązania nie jest znany z góry. W takich przypadkach możesz utworzyć wiązanie za pomocą klasy DataBindingUtil, jak w tym fragmencie kodu:

Kotlin

val viewRoot = LayoutInflater.from(this).inflate(layoutId, parent, attachToParent)
val binding: ViewDataBinding? = DataBindingUtil.bind(viewRoot)

Java

View viewRoot = LayoutInflater.from(this).inflate(layoutId, parent, attachToParent);
ViewDataBinding binding = DataBindingUtil.bind(viewRoot);

Jeśli używasz elementów wiązań danych w adapterze Fragment, ListView lub RecyclerView, możesz skorzystać z metod klas wiązań inflate() lub klasy DataBindingUtil, jak pokazano w tym przykładzie kodu:

Kotlin

val listItemBinding = ListItemBinding.inflate(layoutInflater, viewGroup, false)
// or
val listItemBinding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false)

Java

ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, false);
// or
ListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false);

Wyświetlenia z identyfikatorami

Biblioteka powiązań danych tworzy w klasie powiązania stałe pole dla każdego widoku, który ma identyfikator w układzie. Na przykład Biblioteka powiązań danych tworzy pola firstName i lastName typu TextView na podstawie tego układu:

<layout xmlns:android="http://schemas.android.com/apk/res/android">
   <data>
       <variable name="user" type="com.example.User"/>
   </data>
   <LinearLayout
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.firstName}"
   android:id="@+id/firstName"/>
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.lastName}"
  android:id="@+id/lastName"/>
   </LinearLayout>
</layout>

Biblioteka wyodrębnia widoki, w tym identyfikatory, z hierarchii widoków w jednym przebiegu. Ten mechanizm może być szybszy niż wywoływanie metody findViewById() w przypadku każdego widoku danych w układzie.

Identyfikatory nie są niezbędne, ponieważ nie mają powiązania danych, ale w pewnych sytuacjach dostęp do widoków jest wymagany z poziomu kodu.

Zmienne

Biblioteka powiązań danych generuje metody akcesorów dla każdej zmiennej zadeklarowanej w układzie. Na przykład ten układ generuje metody setter i getter w klasie powiązania zmiennych user, image i note:

<data>
   <import type="android.graphics.drawable.Drawable"/>
   <variable name="user" type="com.example.User"/>
   <variable name="image" type="Drawable"/>
   <variable name="note" type="String"/>
</data>

Strumienie widoków

W przeciwieństwie do zwykłych widoków obiekty ViewStub zaczynają się od widoków niewidocznych. Gdy zostaną wyświetlone lub jawnie powiększone, zastępują się w układzie, zawyżając inny układ.

Obiekt ViewStub znika z hierarchii widoków, więc widok obiektu powiązania też musi zniknąć, aby umożliwić jego zajęcie przez funkcję czyszczenia pamięci. Widoki są ostateczne, obiekt ViewStubProxy zastępuje obiekt ViewStub w wygenerowanej klasie powiązania, zapewniając dostęp do obiektu ViewStub, gdy istnieje, oraz dostęp do rozszerzonej hierarchii widoków, gdy ViewStub jest zwiększony.

Podczas powielania innego układu dla nowego układu musi zostać ustanowione wiązanie. Dlatego ViewStubProxy musi nasłuchiwać parametru ViewStub OnInflateListener i w razie potrzeby ustanowić powiązanie. W danym momencie może istnieć tylko 1 detektor, więc ViewStubProxy umożliwia skonfigurowanie obiektu OnInflateListener, który wywołuje po ustanowieniu powiązania.

Natychmiastowe powiązanie

Gdy zmienna lub obserwowalny obiekt zmienia się, zmiana powiązania jest zaplanowana przed następną klatką. Czasami jednak powiązanie musi zostać wykonane od razu. Aby wymusić wykonanie kodu, użyj metody executePendingBindings().

Zmienne dynamiczne

Czasami konkretna klasa powiązania jest nieznana. Na przykład obiekt RecyclerView.Adapter działający na podstawie dowolnych układów nie zna konkretnej klasy powiązania. Musi przypisać wartość wiązania podczas wywoływania metody onBindViewHolder().

W poniższym przykładzie wszystkie układy, z którymi element RecyclerView wiąże się ze zmienną item, Obiekt BindingHolder ma metodę getBinding(), która zwraca klasę podstawową ViewDataBinding.

Kotlin

override fun onBindViewHolder(holder: BindingHolder, position: Int) {
    item: T = items.get(position)
    holder.binding.setVariable(BR.item, item);
    holder.binding.executePendingBindings();
}

Java

public void onBindViewHolder(BindingHolder holder, int position) {
    final T item = items.get(position);
    holder.getBinding().setVariable(BR.item, item);
    holder.getBinding().executePendingBindings();
}

Wątek w tle

Możesz zmienić model danych w wątku w tle, o ile nie jest on kolekcją. Powiązanie danych lokalizuje każdą zmienną lub pole podczas oceny, aby uniknąć problemów z równoczesnością.

Nazwy klas niestandardowego powiązania

Domyślnie klasa powiązania jest generowana na podstawie nazwy pliku układu rozpoczynającej się wielką literą, usuwaną podkreślenia ( _ ), wielką literą i przyrostkiem słowa Wiązanie. Na przykład plik układu contact_item.xml generuje klasę ContactItemBinding. Klasa jest umieszczana w pakiecie databinding w pakiecie modułu. Jeśli na przykład pakiet modułu to com.example.my.app, klasa powiązania jest umieszczona w pakiecie com.example.my.app.databinding.

Możesz zmieniać nazwy klas powiązań i umieszczać je w różnych pakietach, dostosowując atrybut class elementu data. Na przykład ten układ generuje klasę powiązania ContactItem w pakiecie databinding w bieżącym module:

<data class="ContactItem">
    ...
</data>

Klasę powiązania możesz wygenerować w innym pakiecie, poprzedzając nazwę klasy kropką. Ten przykład generuje klasę powiązania w pakiecie modułu:

<data class=".ContactItem">
    ...
</data>

Możesz też użyć pełnej nazwy pakietu, w którym ma zostać wygenerowana klasa powiązania. Ten przykład tworzy klasę powiązania ContactItem w pakiecie com.example:

<data class="com.example.ContactItem">
    ...
</data>

Dodatkowe materiały

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