Zobacz powiązanie Część systemu Android Jetpack.

Powiązanie widoku danych to funkcja ułatwiająca pisanie kodu, który wchodzi w interakcję z widokami danych. Gdy włączysz powiązanie widoku danych w module, wygeneruje ona klasę powiązania dla każdego pliku układu XML zawartego w tym module. Wystąpienie klasy powiązania zawiera bezpośrednie odwołania do wszystkich widoków, które mają identyfikator w odpowiednim układzie.

W większości przypadków wiązanie wyświetlenia zastępuje atrybut findViewById.

Skonfiguruj

Powiązanie widoku jest włączone dla każdego modułu osobno. Aby włączyć powiązanie widoku w module, ustaw opcję kompilacji viewBinding na true w pliku build.gradle na poziomie modułu, jak pokazano w tym przykładzie:

Odlotowy

android {
    ...
    buildFeatures {
        viewBinding true
    }
}

Kotlin

android {
    ...
    buildFeatures {
        viewBinding = true
    }
}

Jeśli chcesz, aby plik układu był ignorowany podczas generowania klas wiązania, dodaj atrybut tools:viewBindingIgnore="true" do widoku głównego tego pliku układu:

<LinearLayout
        ...
        tools:viewBindingIgnore="true" >
    ...
</LinearLayout>

Wykorzystanie

Jeśli w module jest włączone wiązanie widoku, dla każdego pliku układu XML zawartego w module jest generowana klasa powiązania. Każda klasa powiązania zawiera odwołania do widoku głównego i wszystkich widoków z identyfikatorem. Nazwa klasy powiązania jest generowana przez przekonwertowanie nazwy pliku XML na wielkość liter w formacie Pascal i dodanie na końcu słowa „Binding”.

Weźmy na przykład plik układu o nazwie result_profile.xml, który zawiera:

<LinearLayout ... >
    <TextView android:id="@+id/name" />
    <ImageView android:cropToPadding="true" />
    <Button android:id="@+id/button"
        android:background="@drawable/rounded_button" />
</LinearLayout>

Wygenerowana klasa powiązania to ResultProfileBinding. Ta klasa zawiera 2 pola: TextView o nazwie name i Button o nazwie button. Element ImageView w układzie nie ma identyfikatora, więc nie ma do niego odwołania w klasie powiązania.

Każda klasa powiązania zawiera też metodę getRoot(), która zapewnia bezpośrednie odwołanie do widoku głównego odpowiedniego pliku układu. W tym przykładzie metoda getRoot() w klasie ResultProfileBinding zwraca widok główny LinearLayout.

W sekcjach poniżej pokazujemy, jak korzystać z wygenerowanych klas wiązań w aktywności i fragmentach.

Używanie powiązania widoku danych w działaniach

Aby skonfigurować instancję klasy powiązania na potrzeby działania, wykonaj te czynności w metodzie onCreate() aktywności:

  1. Wywołaj statyczną metodę inflate() uwzględnioną w wygenerowanej klasie powiązania. Spowoduje to utworzenie instancji klasy powiązania, której ma używać działanie.
  2. Możesz uzyskać odniesienie do widoku głównego, wywołując metodę getRoot() lub używając składni właściwości Kotlin.
  3. Przekaż widok główny do setContentView(), aby ustawić go jako widok aktywny na ekranie.

Oto przykład:

Kotlin

private lateinit var binding: ResultProfileBinding

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ResultProfileBinding.inflate(layoutInflater)
    val view = binding.root
    setContentView(view)
}

Java

private ResultProfileBinding binding;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    binding = ResultProfileBinding.inflate(getLayoutInflater());
    View view = binding.getRoot();
    setContentView(view);
}

Możesz teraz użyć wystąpienia klasy powiązania, aby odwołać się do dowolnego z widoków:

Kotlin

binding.name.text = viewModel.name
binding.button.setOnClickListener { viewModel.userClicked() }

Java

binding.name.setText(viewModel.getName());
binding.button.setOnClickListener(new View.OnClickListener() {
    viewModel.userClicked()
});

Używanie powiązania widoku we fragmentach

Aby skonfigurować instancję klasy wiązania do użycia z fragmentem, wykonaj te czynności w metodzie onCreateView() danego fragmentu:

  1. Wywołaj statyczną metodę inflate() uwzględnioną w wygenerowanej klasie powiązania. Spowoduje to utworzenie instancji klasy powiązania, której należy użyć dany fragment.
  2. Możesz uzyskać odniesienie do widoku głównego, wywołując metodę getRoot() lub używając składni właściwości Kotlin.
  3. Przywróć widok główny z metody onCreateView(), aby ustawić go jako widok aktywny na ekranie.

Kotlin

private var _binding: ResultProfileBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    _binding = ResultProfileBinding.inflate(inflater, container, false)
    val view = binding.root
    return view
}

override fun onDestroyView() {
    super.onDestroyView()
    _binding = null
}

Java

private ResultProfileBinding binding;

@Override
public View onCreateView (LayoutInflater inflater,
                          ViewGroup container,
                          Bundle savedInstanceState) {
    binding = ResultProfileBinding.inflate(inflater, container, false);
    View view = binding.getRoot();
    return view;
}

@Override
public void onDestroyView() {
    super.onDestroyView();
    binding = null;
}

Możesz teraz użyć wystąpienia klasy powiązania, aby odwołać się do dowolnego z widoków:

Kotlin

binding.name.text = viewModel.name
binding.button.setOnClickListener { viewModel.userClicked() }

Java

binding.name.setText(viewModel.getName());
binding.button.setOnClickListener(new View.OnClickListener() {
    viewModel.userClicked()
});

Podaj wskazówki dotyczące różnych konfiguracji.

Jeśli zadeklarujesz widoki danych w wielu konfiguracjach, czasami warto użyć innego typu widoku w zależności od konkretnego układu. Oto przykład takiego fragmentu kodu:

# in res/layout/example.xml

<TextView android:id="@+id/user_bio" />

# in res/layout-land/example.xml

<EditText android:id="@+id/user_bio" />

W tym przypadku wygenerowana klasa ujawni pole userBio typu TextView, ponieważ TextView jest wspólną klasą bazową. Ze względu na ograniczenia techniczne generator kodów powiązania widoków nie może tego określić i zamiast tego generuje pole View. Wymaga to późniejszego rzutowania pola za pomocą binding.userBio as TextView.

Aby obejść to ograniczenie, powiązanie widoku obsługuje atrybut tools:viewBindingType, co umożliwia kompilatorowi określenie typu do wykorzystania w wygenerowanym kodzie. W poprzednim przykładzie możesz użyć tego atrybutu, aby kompilator wygenerował pole jako TextView:

# in res/layout/example.xml (unchanged)

<TextView android:id="@+id/user_bio" />

# in res/layout-land/example.xml

<EditText android:id="@+id/user_bio" tools:viewBindingType="TextView" />

W innym przykładzie załóżmy, że masz 2 układy: jeden zawiera element BottomNavigationView, a drugi NavigationRailView. Obie klasy stanowią rozszerzenie NavigationBarView, które zawiera większość szczegółów implementacji. Jeśli Twój kod nie musi wiedzieć, która podklasa występuje w bieżącym układzie, możesz użyć tools:viewBindingType, aby ustawić wygenerowany typ na NavigationBarView w obu układach:

# in res/layout/navigation_example.xml

<BottomNavigationView android:id="@+id/navigation" tools:viewBindingType="NavigationBarView" />

# in res/layout-w720/navigation_example.xml

<NavigationRailView android:id="@+id/navigation" tools:viewBindingType="NavigationBarView" />

Powiązanie widoku danych nie może zweryfikować wartości tego atrybutu podczas generowania kodu. Aby uniknąć błędów podczas kompilacji i czasu działania, wartość musi spełniać te warunki:

  • Wartość musi być klasą dziedziczoną z android.view.View.
  • Wartość musi być klasą nadrzędną tagu, w którym jest umieszczona. Na przykład nie działają te wartości:

      <TextView tools:viewBindingType="ImageView" /> <!-- ImageView is not related to TextView. -->
      <TextView tools:viewBindingType="Button" /> <!-- Button is not a superclass of TextView. -->
    
  • Ostateczny typ musi występować spójnie we wszystkich konfiguracjach.

Różnice w stosunku do metody findViewById

Powiązanie widoku danych ma ważne zalety w porównaniu z używaniem findViewById:

  • Bezpieczeństwo zerowe: ponieważ powiązanie widoku danych tworzy bezpośrednie odwołania do widoków, nie ma ryzyka, że wyjątek wskaźnika o wartości null z powodu nieprawidłowego identyfikatora widoku danych. Poza tym, gdy widok występuje tylko w niektórych konfiguracjach układu, pole zawierające jego odwołanie w klasie powiązania jest oznaczone dyrektywą @Nullable.
  • Bezpieczeństwo typu: typy pól w każdej klasie powiązania są zgodne z widokami danych, do których się odwołują w pliku XML. Nie ma więc ryzyka wyjątku rzutowania klasy.

Te różnice oznaczają niezgodności między układem a kodem, które powodują błędy kompilacji w czasie kompilacji, a nie w czasie działania.

Porównanie z wiązaniem danych

Zarówno widoki powiązań, jak i powiązania danych generują klasy powiązań, których można używać do bezpośredniego odwoływania się do widoków. Jednak wiązanie widoków służy do obsługi prostszych przypadków użycia i daje takie korzyści w porównaniu do wiązań danych:

  • Szybsza kompilacja: wiązanie widoku nie wymaga przetwarzania adnotacji, co przyspiesza kompilację.
  • Łatwość użycia: wiązanie widoku nie wymaga specjalnie otagowanych plików układu XML, dzięki czemu można szybciej zastosować je w aplikacjach. Po włączeniu wiązania widoku w module będzie ono automatycznie stosowane do wszystkich układów tego modułu.

Z drugiej strony wiązanie widoków ma następujące ograniczenia w porównaniu z powiązaniem danych:

Z tego powodu w niektórych przypadkach najlepiej jest używać w projekcie zarówno powiązań widoków, jak i danych. Możesz z nich korzystać w układach, które wymagają funkcji zaawansowanych, i w układach, które ich nie wymagają.

Dodatkowe materiały

Więcej informacji o powiązaniu widoku znajdziesz tutaj:

Próbki

Blogi

Filmy