Guida completa all'iniezione di dipendenza con Hilt su Android

  • Hilt semplifica Dagger fornendo container automatici allineati al ciclo di vita di Android.
  • Consente il disaccoppiamento del codice tramite l'iniezione nel costruttore, i moduli con @Provides e @Binds.
  • Gestisci l'ambito delle istanze utilizzando componenti specifici come SingletonComponent o ActivityComponent.
  • Facilita lo sviluppo di architetture scalabili e testabili, soprattutto in ambienti con Jetpack Compose e MVVM.

Hilt Android

Se sviluppate applicazioni Android, probabilmente vi sarà capitato di dover organizzare meglio le classi per evitare che il progetto precipiti nel caos più totale. È qui che entra in gioco l'iniezione delle dipendenze , un modello di progettazione che, pur potendo inizialmente sembrare una sorta di magia nera, è essenzialmente un modo per fornire a ciascuna classe gli oggetti di cui ha bisogno senza che la classe debba crearli autonomamente.

Hilt arriva in nostro soccorso dalla complessità di Dagger, offrendo un livello superiore che standardizza l'inserimento delle dipendenze . Integrandosi con Jetpack, Hilt gestisce automaticamente container e cicli di vita, permettendoci di concentrarci sulla logica di business anziché spostare oggetti come se fossimo in un trasloco.

Configurazione iniziale dell'ambiente

Per iniziare a usare Hilt, il primo passo è preparare l'ambiente Gradle. È fondamentale aggiungere il plugin hilt-android-gradle-plugin al file di configurazione del progetto. Successivamente, nel file del modulo dell'applicazione, è necessario applicare il plugin e aggiungere le dipendenze corrispondenti, assicurandosi che il compilatore (sia esso kapt o KSP) sia configurato correttamente.

Un dettaglio cruciale è che, affinché tutto funzioni senza intoppi, il progetto deve essere configurato per utilizzare Java 17 (o Java 8 per le versioni precedenti), poiché questo è un prerequisito per la perfetta integrazione tra Hilt e Jetpack Compose . Se notate che il programma non si compila quando attivate il plugin, verificate che le versioni di Kotlin e KSP corrispondano esattamente, poiché anche una minima discrepanza può compromettere l'intero processo di compilazione.

Il cuore di Hilt: la classe applicativa

Qualsiasi app che desideri beneficiare di questa libreria deve avere una classe Application personalizzata. Non basta crearla; deve essere contrassegnata con l' annotazione @HiltAndroidApp . Questa riga attiva la generazione del codice da parte di Hilt e crea il contenitore radice dell'applicazione.

Contesto su Android
Articolo correlato:
Guida completa al contesto in Android: cos'è e come gestirlo

Questo componente di livello superiore è fondamentale perché si collega al ciclo di vita complessivo dell'app e funge da base per tutti gli altri componenti che accedono alle dipendenze definite a questo livello. Ovviamente, non dimenticare di registrare questa classe nel file AndroidManifest.xml utilizzando l'attributo name, altrimenti Hilt passerà completamente inosservato.

Iniezione di dipendenze nei componenti Android

Una volta che l'applicazione è pronta, possiamo iniziare a iniettare le dipendenze in attività, frammenti, viste o servizi. Per fare ciò, utilizziamo l' annotazione @AndroidEntryPoint . Questa annotazione indica a Hilt che questa classe è un punto di ingresso e che deve generare un componente specifico per essa.

Quando vogliamo ottenere una dipendenza specifica all'interno di un'attività, utilizziamo l'iniezione di campi tramite l'annotazione @Inject. È molto importante ricordare che questi campi non possono essere privati ; se si tenta di utilizzare il modificatore private, il compilatore genererà immediatamente un errore. Nel caso di Jetpack Compose, è sufficiente annotare l'Activity radice per poter accedere direttamente ai ViewModel all'interno delle funzioni componibili.

Strategie per definire i collegamenti

Hilt ha bisogno di sapere come creare gli oggetti che richiediamo. Il modo più diretto è l'iniezione tramite costruttore , in cui inseriamo `@Inject` subito prima del costruttore della classe. Questo permette a Hilt di analizzare i parametri e determinare come fornire ciascuna di queste dipendenze.

Tuttavia, ci sono casi in cui non abbiamo il controllo completo sulla classe, ad esempio quando si utilizzano librerie esterne come Retrofit o OkHttpClient. È qui che entrano in gioco i moduli Hilt . Un modulo è una classe annotata con @Module e deve includere @InstallIn per specificare quale componente deve ospitare quella dipendenza.

  • Utilizzo di @Provides: Questo approccio viene utilizzato quando la classe è di terze parti o richiede uno schema di costruzione complesso. Qui definiamo una funzione che restituisce l'istanza necessaria.
  • Utilizzo di @Binds: Questa è l'opzione ideale quando vogliamo collegare un'interfaccia a un'implementazione concreta. È definita come una funzione astratta che dice a Hilt: "quando qualcuno richiede questa interfaccia, forniscigli questa implementazione".

Ambito di applicazione e gestione del ciclo di vita

Per impostazione predefinita, Hilt crea una nuova istanza ogni volta che viene richiesta una dipendenza. Tuttavia, a volte è necessario che un oggetto rimanga invariato per tutta la durata dell'app o di una schermata. Per questo, utilizziamo gli ambiti dei componenti.

Se contrassegniamo una classe con @Singleton e la installiamo in un SingletonComponent, avremo un'unica istanza globale. Se preferiamo che l'oggetto esista solo per la durata dell'attività, utilizziamo @ActivityScoped all'interno di un ActivityComponent. È fondamentale non abusare degli scope, poiché mantenere gli oggetti in memoria troppo a lungo può influire negativamente sulle prestazioni dell'applicazione.

Casi speciali e qualificatori

A volte è necessario iniettare due implementazioni diverse della stessa interfaccia. Per evitare di sovraccaricare il compilatore, si utilizzano i qualificatori . Un qualificatore è essenzialmente un'annotazione personalizzata utilizzata per etichettare un binding specifico, consentendo di distinguere, ad esempio, tra un client HTTP per l'autenticazione e uno per le richieste generiche.

mvvm
Articolo correlato:
MVVM: il modello di architettura software definitivo per le app moderne

Inoltre, Hilt semplifica le cose con qualificatori predefiniti come @ApplicationContext e @ActivityContext, permettendoci di ottenere il contesto Android senza dover configurare manualmente i moduli. Infine, per le classi che Hilt non supporta nativamente (come i ContentProvider), possiamo usare l' annotazione @EntryPoint , creando un ponte manuale per estrarre le dipendenze dal grafo di Hilt. Condividi queste informazioni in modo che più utenti possano conoscerle.


Aggiungi come fonte preferita in Google