Wyświetl powiązanie   Należy do Android Jetpack.

Powiązanie widoku to funkcja, która ułatwia pisanie kodu, który wchodzi w interakcje z widokami. Gdy w module włączysz wiązanie widoku, zostanie wygenerowana klasa wiązania dla każdego pliku układu XML znajdującego się w tym module. Występujący instancja klasy wią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 widoku zastępuje findViewById.

Konfiguracja

Powiązanie wyświetlania jest włączane w poszczególnych modułach. Aby włączyć wiązanie widoku w module, w pliku build.gradle na poziomie modułu ustaw opcję kompilacji viewBinding na true, jak pokazano w tym przykładzie:

Groovy

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 wyższego poziomu tego pliku układu:

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

Wykorzystanie

Jeśli w przypadku modułu włączone jest wiązanie widoku, dla każdego pliku układu XML, który zawiera moduł, generowana jest klasa wiązania. Każda klasa wiązania zawiera odwołania do widoku wyższego poziomu i wszystkich widoków, które mają identyfikator. Nazwa klasy wiązania jest generowana przez konwersję nazwy pliku XML na Pascal Case 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 binding ma nazwę ResultProfileBinding. Ta klasa ma 2 pola: TextView o nazwie nameButton o nazwie button. Element ImageView w szablonie nie ma identyfikatora, więc nie ma do niego odwołania w klasie wiązania.

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

W następnych sekcjach pokazujemy, jak używać wygenerowanych klas wiązania w aktywnościach i fragmentach.

Używanie powiązania widoku w czynnościach

Aby skonfigurować instancję klasy wiązania do użycia w ramach aktywności, wykonaj te czynności w metodzie aktywności onCreate():

  1. Wywołaj statyczną metodę inflate() zawartą w wygenerowanej klasie powiązania. W ten sposób tworzy instancję klasy wiązania, z której będzie korzystać aktywność.
  2. Aby uzyskać odwołanie do widoku głównego, wywołaj metodę getRoot() lub użyj składni właściwości Kotlin.
  3. Przekaż widok wyższy do widoku okna setContentView(), aby uczynić go widokiem aktywnym na ekranie.

Te kroki są pokazane w tym przykładzie:

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żywać instancji klasy powiązania do odwoływania się do dowolnego widoku:

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 w fragmentach

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

  1. Wywołaj statyczną metodę inflate() zawartą w wygenerowanej klasie powiązania. Spowoduje to utworzenie instancji klasy wiązania, której fragment ma używać.
  2. Odwołaj się do widoku głównego, wywołując metodę getRoot() lub używając składni właściwości Kotlin.
  3. Zwraca widok wyższego poziomu z metody onCreateView(), aby uczynić go widokiem aktywnym 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żywać instancji klasy powiązania do odwoływania się do dowolnego widoku:

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

Podawanie wskazówek dotyczących różnych konfiguracji

Gdy deklarujesz widoki w różnych konfiguracjach, czasami warto użyć innego typu widoku w zależności od konkretnego układu. Przykładowy fragment 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 może udostępniać pole userBio typu TextView, ponieważ TextView jest wspólną klasą podstawową. Ze względu na ograniczenia techniczne generator kodu do wiązania widoku nie może tego określić i zamiast tego generuje pole View. Wymaga to późniejszego zamieniania pola za pomocą funkcji binding.userBio as TextView.

Aby obejść to ograniczenie, możesz użyć atrybutu tools:viewBindingType, aby poinformować kompilator, jakiego typu użyć w wygenerowanym kodzie. W poprzednim przykładzie możesz użyć tego atrybutu, aby skłonić kompilator do wygenerowania pola 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" />

Załóżmy, że masz 2 układy: jeden zawiera BottomNavigationView, a drugi – NavigationRailView. Obie klasy rozszerzają klasę NavigationBarView, która zawiera większość szczegółów implementacji. Jeśli Twój kod nie musi wiedzieć, która podklasa jest obecna 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" />

Podczas generowania kodu widok nie może sprawdzić wartości tego atrybutu. Aby uniknąć błędów w czasie kompilacji i wykonywania, wartość musi spełniać te warunki:

  • Wartość musi być klasą dziedziczącą z android.view.View.
  • Wartość musi być superklasą tagu, na którym jest umieszczona. Na przykład te wartości nie działają:

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

Różnice w porównaniu z findViewById

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

  • Bezpieczeństwo w przypadku wartości null: ponieważ wiązanie widoku tworzy bezpośrednie odwołania do widoków, nie ma ryzyka wyjątku wskaźnika null z powodu nieprawidłowego identyfikatora widoku. Dodatkowo, gdy widok występuje tylko w niektórych konfiguracjach układu, pole zawierające jego odwołanie w klasie wiążącej jest oznaczone symbolem @Nullable.
  • Bezpieczeństwo typów: pola w każdej klasie powiązania mają typy pasujące do widoków, do których odwołują się w pliku XML. Oznacza to, że nie ma ryzyka wyjątku od zasady „classcast”.

Te różnice oznaczają, że niespójności między układem a kodem powodują, że kompilacja nie powiedzie się w czasie kompilacji, a w czasie wykonywania.

Porównanie z wiązaniem danych

Wiązanie widoku i wiązanie danych generują klasy wiązania, których możesz używać do bezpośredniego odwoływania się do widoków. Wiązanie widoku jest jednak przeznaczone do obsługi prostszych przypadków użycia i daje te korzyści w porównaniu z wiązaniem danych:

  • Szybsza kompilacja: wiązanie widoku nie wymaga przetwarzania adnotacji, więc czas kompilacji jest krótszy.
  • Łatwość użycia: wiązanie widoku nie wymaga specjalnie otagowanych plików układu XML, dzięki czemu szybciej można je zastosować w aplikacjach. Gdy włączysz widok wiązania w module, zostanie on automatycznie zastosowany do wszystkich jego układów.

Z drugiej strony, wiązanie widoku ma w porównaniu z wiązaniem danych te ograniczenia:

Z tego powodu w niektórych przypadkach lepiej jest w projekcie używać zarówno widocznych, jak i danych połączeń. Możesz używać powiązania danych w układach, które wymagają funkcji zaawansowanych, i użyć powiązania widoku w układach, które nie wymagają takich funkcji.

Dodatkowe materiały

Więcej informacji o wiązaniu widoku znajdziesz w tych dodatkowych materiałach:

Blogi

Filmy