Visualizza associazione   Componente di Android Jetpack.

Il binding delle visualizzazioni è una funzionalità che semplifica la scrittura di codice che interagisce con le visualizzazioni. Una volta attivata la funzionalità di binding delle visualizzazioni in un modulo, viene generata una classe di binding per ogni file di layout XML presente nel modulo. Un'istanza di una classe di binding contiene riferimenti diretti a tutte le visualizzazioni che hanno un ID nel layout corrispondente.

Nella maggior parte dei casi, il binding della vista sostituisce findViewById.

Configura

L'associazione delle visualizzazioni è attivata su base modulare. Per attivare il binding delle visualizzazioni in un modulo, imposta l'opzione di compilazione viewBinding su true nel file build.gradle a livello di modulo, come mostrato nell'esempio seguente:

Groovy

android {
    ...
    buildFeatures {
        viewBinding true
    }
}

Kotlin

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

Se vuoi che un file di layout venga ignorato durante la generazione delle classi di binding, aggiungi l'attributo tools:viewBindingIgnore="true" alla vista principale del file di layout:

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

Utilizzo

Se la visualizzazione del binding è attivata per un modulo, viene generata una classe di binding per ogni file di layout XML contenuto nel modulo. Ogni classe di binding contiene riferimenti alla vista principale e a tutte le viste con un ID. Il nome della classe di binding viene generato convertendo il nome del file XML in lettere maiuscole e aggiungendo la parola "Binding" alla fine.

Ad esempio, considera un file di layout denominato result_profile.xml che contiene quanto segue:

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

La classe di binding generata si chiama ResultProfileBinding. Questa classe ha due campi: un TextView chiamato name e un Button chiamato button. Il ImageView nel layout non ha ID, pertanto non vi è alcun riferimento nella classe di binding.

Ogni classe di binding include anche un metodo getRoot(), che fornisce un riferimento diretto alla vista principale del file di layout corrispondente. In questo esempio, il metodo getRoot() nella classe ResultProfileBinding restituisce la vista radice LinearLayout.

Le sezioni seguenti mostrano l'utilizzo delle classi di binding generate in attività e frammenti.

Utilizzare l'associazione delle visualizzazioni nelle attività

Per configurare un'istanza della classe di binding da utilizzare con un'attività, svolgi i seguenti passaggi nel metodo onCreate() dell'attività:

  1. Chiama il metodo inflate() statico incluso nella classe di binding generata. Viene creata un'istanza della classe di binding da utilizzare per l'attività.
  2. Ottieni un riferimento alla vista principale chiamando il metodo getRoot() o utilizzando la sintassi della proprietà Kotlin.
  3. Passa la visualizzazione principale a setContentView() per impostarla come visualizzazione attiva sullo schermo.

Questi passaggi sono illustrati nell'esempio seguente:

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

Ora puoi utilizzare l'istanza della classe di binding per fare riferimento a qualsiasi visualizzazione:

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

Utilizzare l'associazione delle visualizzazioni nei frammenti

Per configurare un'istanza della classe di binding da utilizzare con un frammento, svolgi i seguenti passaggi nel metodo onCreateView() del frammento:

  1. Chiama il metodo inflate() statico incluso nella classe di binding generata. Viene creata un'istanza della classe di binding da utilizzare per il frammento.
  2. Ottieni un riferimento alla vista principale chiamando il metodo getRoot() o utilizzando la sintassi della proprietà Kotlin.
  3. Restituire la visualizzazione principale dal metodo onCreateView() per renderla la visualizzazione attiva sullo schermo.

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

Ora puoi utilizzare l'istanza della classe di binding per fare riferimento a qualsiasi visualizzazione:

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

Fornire suggerimenti per configurazioni diverse

Quando dichiari le visualizzazioni in più configurazioni, a volte può essere utile utilizzare un tipo di visualizzazione diverso a seconda del layout specifico. Il seguente snippet di codice ne mostra un esempio:

# in res/layout/example.xml

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

# in res/layout-land/example.xml

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

In questo caso, potresti aspettarti che la classe generata esponga un campo userBio di tipo TextView, perché TextView è la classe di base comune. A causa di limitazioni tecniche, il generatore di codice di binding delle visualizzazioni non può determinarlo e genera un campo View. Ciò richiede il trasferimento del campo in un secondo momento con binding.userBio as TextView.

Per aggirare questa limitazione, la visualizzazione della proprietà supporta un attributo tools:viewBindingType, che ti consente di indicare al compilatore il tipo da utilizzare nel codice generato. Nell'esempio precedente, puoi utilizzare questo attributo per fare in modo che il compilatore generi il campo come 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" />

In un altro esempio, supponiamo che tu abbia due layout, uno contenente un BottomNavigationView e un altro contenente un NavigationRailView. Entrambe le classi estendono NavigationBarView, che contiene la maggior parte dei dettagli di implementazione. Se il codice non deve sapere esattamente quale sottoclasse è presente nel layout corrente, puoi utilizzare tools:viewBindingType per impostare il tipo generato su NavigationBarView in entrambi i layout:

# 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" />

Il binding delle visualizzazioni non può convalidare il valore di questo attributo durante la generazione del codice. Per evitare errori di compilazione e di runtime, il valore deve soddisfare le seguenti condizioni:

  • Il valore deve essere una classe che eredita da android.view.View.
  • Il valore deve essere un superclasse del tag in cui è inserito. Ad esempio, i seguenti valori non funzionano:

      <TextView tools:viewBindingType="ImageView" /> <!-- ImageView is not related to TextView. -->
      <TextView tools:viewBindingType="Button" /> <!-- Button is not a superclass of TextView. -->
    
  • Il tipo finale deve essere risolto in modo coerente in tutte le configurazioni.

Differenze rispetto a findViewById

Il binding delle visualizzazioni presenta vantaggi importanti rispetto all'utilizzo di findViewById:

  • Sicurezza di null:poiché il binding delle visualizzazioni crea riferimenti diretti alle visualizzazioni, non c'è il rischio di un'eccezione di puntatore null a causa di un ID visualizzazione non valido. Inoltre, quando una visualizzazione è presente solo in alcune configurazioni di un layout, il campo contenente il relativo riferimento nella classe di binding è contrassegnato con @Nullable.
  • Sicurezza del tipo:i campi di ogni classe di binding hanno tipi corrispondenti alle visualizzazioni a cui fanno riferimento nel file XML. Ciò significa che non c'è il rischio di un'eccezione di errato invio di un valore a un tipo.

Queste differenze comportano incompatibilità tra il layout e il codice, con conseguente fallimento della compilazione anziché del runtime.

Confronto con l'associazione di dati

Sia il binding delle visualizzazioni sia il binding dei dati generano classi di binding che puoi utilizzare per fare riferimento direttamente alle visualizzazioni. Tuttavia, il binding delle visualizzazioni è progettato per gestire casi d'uso più semplici e offre i seguenti vantaggi rispetto al binding dei dati:

  • Compilazione più rapida: il binding delle visualizzazioni non richiede l'elaborazione delle annotazioni, pertanto i tempi di compilazione sono più rapidi.
  • Facilità d'uso:il binding delle visualizzazioni non richiede file di layout XML con tag speciali, quindi è più veloce da adottare nelle app. Una volta attivata la associazione delle visualizzazioni in un modulo, questa viene applicata automaticamente a tutti i layout del modulo.

D'altra parte, il binding delle viste presenta le seguenti limitazioni rispetto al binding dei dati:

Per questi motivi, in alcuni casi è preferibile utilizzare sia il binding della vista sia il binding dei dati in un progetto. Puoi utilizzare il binding dei dati nei layout che richiedono funzionalità avanzate e il binding delle visualizzazioni nei layout che non lo richiedono.

Risorse aggiuntive

Per scoprire di più sul binding delle visualizzazioni, consulta le seguenti risorse aggiuntive:

Blog

Video