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 name
i Button
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()
:
- 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ść. - Aby uzyskać odwołanie do widoku głównego, wywołaj metodę
getRoot()
lub użyj składni właściwości Kotlin. - 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:
- Wywołaj statyczną metodę
inflate()
zawartą w wygenerowanej klasie powiązania. Spowoduje to utworzenie instancji klasy wiązania, której fragment ma używać. - Odwołaj się do widoku głównego, wywołując metodę
getRoot()
lub używając składni właściwości Kotlin. - 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:
- Powiązanie widoku nie obsługuje zmiennych ani wyrażeń układu, więc nie można go używać do deklarowania dynamicznych treści interfejsu bezpośrednio z plików układu XML.
- Wiązanie widoku nie obsługuje dwukierunkowego wiązania danych.
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
Polecane dla Ciebie
- Uwaga: tekst linku jest wyświetlany, gdy obsługa JavaScript jest wyłączona
- Migracja z syntetycznych danych Kotlina na Jetpack View Binding
- Układy i wyrażenia wiążące
- Architektura aplikacji: warstwa interfejsu – wprowadzenie – deweloperzy Androida