Iniezione di dipendenze con Hilt

Hilt è una libreria di dipendenza per Android che riduce il codice boilerplate necessario per eseguire l'iniezione di dipendenze manuale nel progetto. Eseguire dipendenze manuali iniezione di codice richiede la creazione di ogni classe e le sue dipendenze a mano e usare i container per riutilizzare e gestire le dipendenze.

Hilt offre un modo standard per utilizzare DI nell'applicazione fornendo container per ogni classe Android del tuo progetto e la gestione dei relativi cicli di vita automaticamente. Hilt è basato sulla popolare libreria DI Dagger per trarre vantaggio dalla correttezza in fase di compilazione, dalle prestazioni in fase di esecuzione, dalla scalabilità e dal supporto di Android Studio offerti da Dagger. Per ulteriori informazioni, consulta Hilt e Pugna.

Questa guida illustra i concetti di base di Hilt e dei relativi contenitori generati. it include anche una dimostrazione di come eseguire il bootstrap di un'app esistente per utilizzare Hilt.

Aggiunta di dipendenze

Innanzitutto, aggiungi il plug-in hilt-android-gradle-plugin alla directory principale del progetto build.gradle file:

plugins {
  ...
  id 'com.google.dagger.hilt.android' version '2.51.1' apply false
}
plugins {
  ...
  id("com.google.dagger.hilt.android") version "2.51.1" apply false
}

Quindi, applica il plug-in Gradle e aggiungi queste dipendenze nel file app/build.gradle:

...
plugins {
  id 'kotlin-kapt'
  id 'com.google.dagger.hilt.android'
}

android {
  ...
}

dependencies {
  implementation "com.google.dagger:hilt-android:2.51.1"
  kapt "com.google.dagger:hilt-compiler:2.51.1"
}

// Allow references to generated code
kapt {
  correctErrorTypes true
}
plugins {
  id("kotlin-kapt")
  id("com.google.dagger.hilt.android")
}

android {
  ...
}

dependencies {
  implementation("com.google.dagger:hilt-android:2.51.1")
  kapt("com.google.dagger:hilt-android-compiler:2.51.1")
}

// Allow references to generated code
kapt {
  correctErrorTypes = true
}

Hilt utilizza le funzionalità di Java 8. Per attivare Java 8 nel tuo progetto, aggiungi quanto segue al file app/build.gradle:

android {
  ...
  compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }
}
android {
  ...
  compileOptions {
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
  }
}

Classe dell'applicazione Hilt

Tutte le app che utilizzano Hilt devono contenere un'etichetta Application classe annotata con @HiltAndroidApp.

@HiltAndroidApp attiva la generazione di codice di Hilt, inclusa una classe base per l'applicazione che funge da container delle dipendenze a livello di applicazione.

KotlinJava
@HiltAndroidApp
class ExampleApplication : Application() { ... }
@HiltAndroidApp
public class ExampleApplication extends Application { ... }

Questo componente Hilt generato è collegato all'oggetto Application dell'oggetto ciclo di vita e fornisce dipendenze. Inoltre, è il componente principale dell'app, il che significa che gli altri componenti possono accedere alle dipendenze che fornisce.

Inserisci le dipendenze nelle classi Android

Dopo aver configurato Hilt nella classe Application e in un livello a livello di applicazione è disponibile, Hilt può fornire dipendenze ad altre classi Android che presentano l'annotazione @AndroidEntryPoint:

KotlinJava
@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() { ... }
@AndroidEntryPoint
public class ExampleActivity extends AppCompatActivity { ... }

Al momento Hilt supporta le seguenti classi per Android:

  • Application (utilizzando @HiltAndroidApp)
  • ViewModel (utilizzando @HiltViewModel)
  • Activity
  • Fragment
  • View
  • Service
  • BroadcastReceiver

Se a un corso Android annotati con @AndroidEntryPoint, devi anche annotare le classi di Android che dipendono da questo. Ad esempio, se aggiungi un'annotazione , devi anche annotare tutte le attività in cui utilizzi .

@AndroidEntryPoint genera un singolo componente Hilt per ogni classe Android nel progetto. Questi componenti possono ricevere dipendenze rispettive classi padre, come descritto in Componente della gerarchia.

Per ottenere le dipendenze da un componente, utilizza l'annotazione @Inject per eseguire l'iniezione di campo:

KotlinJava
@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() {

  @Inject lateinit var analytics: AnalyticsAdapter
  ...
}
@AndroidEntryPoint
public class ExampleActivity extends AppCompatActivity {

  @Inject
  AnalyticsAdapter analytics;
  ...
}

Le classi iniettate da Hilt possono avere altre classi di base che utilizzano anche l'iniezione. Queste classi non hanno bisogno dell'annotazione @AndroidEntryPoint, se sono in modo astratto.

Per scoprire di più sul callback del ciclo di vita in cui viene iniettata una classe Android, consulta la sezione Cicli di vita dei componenti.

Definisci associazioni Hilt

Per eseguire l'inserimento del campo, Hilt deve sapere come fornire istanze le dipendenze necessarie dal componente corrispondente. Una associazione contiene le informazioni necessarie per fornire istanze di un tipo come dipendenza.

Un modo per fornire informazioni di associazione a Hilt è l'inserimento del costruttore. Utilizza l'annotazione @Inject sul costruttore di una classe per indicare a Hilt come fornire le istanze di quella classe:

KotlinJava
class AnalyticsAdapter @Inject constructor(
  private val service: AnalyticsService
) { ... }
public class AnalyticsAdapter {

  private final AnalyticsService service;

  @Inject
  AnalyticsAdapter(AnalyticsService service) {
    this.service = service;
  }
  ...
}

I parametri di un costruttore annotato di una classe sono le dipendenze di quella classe. Nell'esempio, AnalyticsAdapter ha AnalyticsService come la dipendenza. Pertanto, Hilt deve anche sapere come fornire istanze di AnalyticsService.

Moduli Hilt

A volte un tipo non può essere inserito dal costruttore. Ciò può accadere per più motivi. Ad esempio, non puoi iniettare un'interfaccia tramite il costruttore. Inoltre, non puoi eseguire l'iniezione di un tipo che non possiedi, ad esempio una classe di una libreria esterna. In questi casi, puoi fornire a Hilt informazioni di associazione mediante i moduli Hilt.

Un modulo Hilt è una classe annotata con @Module. Come un modulo Dagger, informa Hilt su come fornire istanze di determinati tipi. A differenza dei moduli Dagger, devi annotare i moduli Hilt con @InstallIn per indicare a Hilt in quale classe Android verrà utilizzato o installato ciascun modulo.

Le dipendenze fornite nei moduli Hilt sono disponibili in tutti i componenti generati associati alla classe Android in cui installi il modulo Hilt.

Esegui l'iniezione di istanze di interfaccia con @Binds

Considera l'esempio AnalyticsService. Se AnalyticsService è un'interfaccia, non puoi iniettarlo tramite il costruttore. Fornisci invece a Hilt le informazioni di associazione creando una funzione astratta annotata con @Binds all'interno di un modulo Hilt.

L'annotazione @Binds indica a Hilt quale implementazione utilizzare quando deve fornire un'istanza di un'interfaccia.

La funzione annotata fornisce le seguenti informazioni a Hilt:

  • Il tipo di ritorno della funzione indica a Hilt di quale interfaccia fornisce la funzione le istanze.
  • Il parametro della funzione indica a Hilt quale implementazione fornire.
KotlinJava
interface AnalyticsService {
  fun analyticsMethods()
}

// Constructor-injected, because Hilt needs to know how to
// provide instances of AnalyticsServiceImpl, too.
class AnalyticsServiceImpl @Inject constructor(
  ...
) : AnalyticsService { ... }

@Module
@InstallIn(ActivityComponent::class)
abstract class AnalyticsModule {

  @Binds
  abstract fun bindAnalyticsService(
    analyticsServiceImpl: AnalyticsServiceImpl
  ): AnalyticsService
}
public interface AnalyticsService {
  void analyticsMethods();
}

// Constructor-injected, because Hilt needs to know how to
// provide instances of AnalyticsServiceImpl, too.
public class AnalyticsServiceImpl implements AnalyticsService {
  ...
  @Inject
  AnalyticsServiceImpl(...) {
    ...
  }
}

@Module
@InstallIn(ActivityComponent.class)
public abstract class AnalyticsModule {

  @Binds
  public abstract AnalyticsService bindAnalyticsService(
    AnalyticsServiceImpl analyticsServiceImpl
  );
}

Il modulo Hilt AnalyticsModule è annotato con @InstallIn(ActivityComponent.class) perché vuoi che Hilt inietti questa dipendenza in ExampleActivity. Questa annotazione indica che tutti le dipendenze in AnalyticsModule sono disponibili in tutte le attività dell'app.

Iniettare istanze con @Provides

Le interfacce non sono l'unico caso in cui non puoi iniettare un tipo tramite il costruttore. L'iniezione del costruttore non è possibile anche se non possiedi la classe perché proviene da una libreria esterna (classi come Retrofit, OkHttpClient o database Room) o se le istanze devono essere create con il pattern di compilatore.

Considera l'esempio precedente. Se non possiedi direttamente AnalyticsService , puoi indicare a Hilt come fornire istanze di questo tipo creando un'istanza all'interno di un modulo Hilt e annotarla con @Provides.

La funzione annotata fornisce le seguenti informazioni a Hilt:

  • Il tipo restituito dalla funzione indica a Hilt il tipo di funzione che fornisce alle istanze di.
  • I parametri della funzione indicano a Hilt le dipendenze del tipo corrispondente.
  • Il corpo della funzione indica a Hilt come fornire un'istanza del di testo. Hilt esegue il corpo della funzione ogni volta che deve fornire una un'istanza di quel tipo.
KotlinJava
@Module
@InstallIn(ActivityComponent::class)
object AnalyticsModule {

  @Provides
  fun provideAnalyticsService(
    // Potential dependencies of this type
  ): AnalyticsService {
      return Retrofit.Builder()
               .baseUrl("https://example.com")
               .build()
               .create(AnalyticsService::class.java)
  }
}
@Module
@InstallIn(ActivityComponent.class)
public class AnalyticsModule {

  @Provides
  public static AnalyticsService provideAnalyticsService(
    // Potential dependencies of this type
  ) {
      return new Retrofit.Builder()
               .baseUrl("https://example.com")
               .build()
               .create(AnalyticsService.class);
  }
}

Fornisci più associazioni per lo stesso tipo

Se hai bisogno che Hilt fornisca implementazioni diverse dello stesso come dipendenze, devi fornire a Hilt più associazioni. Puoi Definisci più associazioni per lo stesso tipo con i qualificatori.

Un qualificatore è un'annotazione che utilizzi per identificare una specifica associazione per un tipo quando sono definite più associazioni per quel tipo.

Considera l'esempio. Se devi intercettare le chiamate a AnalyticsService, puoi utilizzare un oggetto OkHttpClient con un intercettatore. Per altri servizi, potrebbe essere necessario intercettare le chiamate in modo diverso. In questo caso, devi dire a Hilt come fornire due implementazioni diverse di OkHttpClient.

Innanzitutto, definisci i qualificatori che utilizzerai per annotare @Binds o @Provides metodi:

KotlinJava
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class AuthInterceptorOkHttpClient

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class OtherInterceptorOkHttpClient
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
private @interface AuthInterceptorOkHttpClient {}

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
private @interface OtherInterceptorOkHttpClient {}

Hilt deve quindi sapere come fornire un'istanza del tipo che corrisponde con ogni qualificatore. In questo caso, potresti utilizzare un modulo Hilt con @Provides. Entrambi i metodi hanno lo stesso tipo restituito, ma i qualificatori li etichettano come due associazioni diverse:

KotlinJava
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {

  @AuthInterceptorOkHttpClient
  @Provides
  fun provideAuthInterceptorOkHttpClient(
    authInterceptor: AuthInterceptor
  ): OkHttpClient {
      return OkHttpClient.Builder()
               .addInterceptor(authInterceptor)
               .build()
  }

  @OtherInterceptorOkHttpClient
  @Provides
  fun provideOtherInterceptorOkHttpClient(
    otherInterceptor: OtherInterceptor
  ): OkHttpClient {
      return OkHttpClient.Builder()
               .addInterceptor(otherInterceptor)
               .build()
  }
}
@Module
@InstallIn(ActivityComponent.class)
public class NetworkModule {

  @AuthInterceptorOkHttpClient
  @Provides
  public static OkHttpClient provideAuthInterceptorOkHttpClient(
    AuthInterceptor authInterceptor
  ) {
      return new OkHttpClient.Builder()
                   .addInterceptor(authInterceptor)
                   .build();
  }

  @OtherInterceptorOkHttpClient
  @Provides
  public static OkHttpClient provideOtherInterceptorOkHttpClient(
    OtherInterceptor otherInterceptor
  ) {
      return new OkHttpClient.Builder()
                   .addInterceptor(otherInterceptor)
                   .build();
  }
}

Puoi inserire il tipo specifico di cui hai bisogno annotando il campo oppure con il qualificatore corrispondente:

KotlinJava
// As a dependency of another class.
@Module
@InstallIn(ActivityComponent::class)
object AnalyticsModule {

  @Provides
  fun provideAnalyticsService(
    @AuthInterceptorOkHttpClient okHttpClient: OkHttpClient
  ): AnalyticsService {
      return Retrofit.Builder()
               .baseUrl("https://example.com")
               .client(okHttpClient)
               .build()
               .create(AnalyticsService::class.java)
  }
}

// As a dependency of a constructor-injected class.
class ExampleServiceImpl @Inject constructor(
  @AuthInterceptorOkHttpClient private val okHttpClient: OkHttpClient
) : ...

// At field injection.
@AndroidEntryPoint
class ExampleActivity: AppCompatActivity() {

  @AuthInterceptorOkHttpClient
  @Inject lateinit var okHttpClient: OkHttpClient
}
// As a dependency of another class.
@Module
@InstallIn(ActivityComponent.class)
public class AnalyticsModule {

  @Provides
  public static AnalyticsService provideAnalyticsService(
    @AuthInterceptorOkHttpClient OkHttpClient okHttpClient
  ) {
      return new Retrofit.Builder()
                  .baseUrl("https://example.com")
                  .client(okHttpClient)
                  .build()
                  .create(AnalyticsService.class);
  }
}

// As a dependency of a constructor-injected class.
public class ExampleServiceImpl ... {

  private final OkHttpClient okHttpClient;

  @Inject
  ExampleServiceImpl(@AuthInterceptorOkHttpClient OkHttpClient okHttpClient) {
    this.okHttpClient = okHttpClient;
  }
}

// At field injection.
@AndroidEntryPoint
public class ExampleActivity extends AppCompatActivity {

  @AuthInterceptorOkHttpClient
  @Inject
  OkHttpClient okHttpClient;
  ...
}

Come best practice, se aggiungi un qualificatore a un tipo, aggiungi i qualificatori a tutti i modi possibili per fornire la dipendenza. Lasciare l'implementazione di base o comune senza un qualificatore è soggetto a errori e potrebbe comportare l'iniezione da parte di Hilt della dipendenza sbagliata.

Qualificatori predefiniti in Hilt

Hilt fornisce alcuni qualificatori predefiniti. Ad esempio, poiché potresti aver bisogno Context dall'applicazione o dall'attività, Hilt fornisce Qualificatori @ApplicationContext e @ActivityContext.

Supponiamo che la classe AnalyticsAdapter dell'esempio abbia bisogno del contesto di l'attività. Il codice seguente mostra come fornire il contesto dell'attività a AnalyticsAdapter:

KotlinJava
class AnalyticsAdapter @Inject constructor(
    @ActivityContext private val context: Context,
    private val service: AnalyticsService
) { ... }
public class AnalyticsAdapter {

  private final Context context;
  private final AnalyticsService service;

  @Inject
  AnalyticsAdapter(
    @ActivityContext Context context,
    AnalyticsService service
  ) {
    this.context = context;
    this.service = service;
  }
}

Per altre associazioni predefinite disponibili in Hilt, consulta la sezione Predefinita dei componenti associazioni.

Componenti generati per classi Android

Per ogni classe Android in cui puoi eseguire l'iniezione di campo, è presente un componente Hilt associato a cui puoi fare riferimento nell'annotazione @InstallIn. Ciascun componente Hilt è responsabile dell'inserimento delle proprie associazioni nel classe Android corrispondente.

Gli esempi precedenti hanno dimostrato l'utilizzo di ActivityComponent in Hilt moduli.

Hilt fornisce i seguenti componenti:

Componente Hilt Iniettore per
SingletonComponent Application
ActivityRetainedComponent N/D
ViewModelComponent ViewModel
ActivityComponent Activity
FragmentComponent Fragment
ViewComponent View
ViewWithFragmentComponent View annotato con @WithFragmentBindings
ServiceComponent Service

Durata dei componenti

Hilt crea ed elimina automaticamente le istanze delle classi dei componenti generate in base al ciclo di vita delle classi Android corrispondenti.

Componente generato Ora di creazione: Eliminata il giorno
SingletonComponent Application#onCreate() Application eliminato
ActivityRetainedComponent Activity#onCreate() Activity#onDestroy()
ViewModelComponent ViewModel creato ViewModel distrutta
ActivityComponent Activity#onCreate() Activity#onDestroy()
FragmentComponent Fragment#onAttach() Fragment#onDestroy()
ViewComponent View#super() View eliminato
ViewWithFragmentComponent View#super() View distrutta
ServiceComponent Service#onCreate() Service#onDestroy()

Ambiti dei componenti

Per impostazione predefinita, tutte le associazioni in Hilt sono senza ambito. Ciò significa che ogni volta che la tua app richiede la associazione, Hilt crea una nuova istanza del tipo necessario.

Nell'esempio, ogni volta che Hilt fornisce AnalyticsAdapter come dipendenza a un altro tipo o tramite l'iniezione di campo (come in ExampleActivity), fornisce una nuova istanza di AnalyticsAdapter.

Tuttavia, Hilt consente anche di limitare l'ambito di una associazione a un determinato componente. Elsa crea un'associazione con ambito solo una volta per istanza del componente che è limitato l'ambito dell'associazione e tutte le relative richieste condividono la stessa istanza.

La tabella seguente elenca le annotazioni dell'ambito per ogni componente generato:

Corso Android Componente generato Ambito
Application SingletonComponent @Singleton
Activity ActivityRetainedComponent @ActivityRetainedScoped
ViewModel ViewModelComponent @ViewModelScoped
Activity ActivityComponent @ActivityScoped
Fragment FragmentComponent @FragmentScoped
View ViewComponent @ViewScoped
View annotato con @WithFragmentBindings ViewWithFragmentComponent @ViewScoped
Service ServiceComponent @ServiceScoped

Nell'esempio, se limiti AnalyticsAdapter all'ambito ActivityComponent utilizzando @ActivityScoped, Hilt fornisce la stessa istanza di AnalyticsAdapter durante l'intero ciclo di vita dell'attività corrispondente:

KotlinJava
@ActivityScoped
class AnalyticsAdapter @Inject constructor(
  private val service: AnalyticsService
) { ... }
@ActivityScoped
public class AnalyticsAdapter {

  private final AnalyticsService service;

  @Inject
  AnalyticsAdapter(AnalyticsService service) {
    this.service = service;
  }
  ...
}

Supponiamo che AnalyticsService abbia uno stato interno che richiede lo stesso di essere utilizzato ogni volta, non solo in ExampleActivity, ma ovunque in l'app. In questo caso, è appropriato applicare l'ambito AnalyticsService alla SingletonComponent. Il risultato è che ogni volta che il componente deve fornire un'istanza di AnalyticsService, fornisce sempre la stessa istanza.

L'esempio seguente mostra come definire l'ambito di una associazione a un componente in un modulo Hilt. L'ambito di un'associazione deve corrispondere all'ambito del componente in cui si trova quindi, in questo esempio, devi installare AnalyticsService SingletonComponent anziché ActivityComponent:

KotlinJava
// If AnalyticsService is an interface.
@Module
@InstallIn(SingletonComponent::class)
abstract class AnalyticsModule {

  @Singleton
  @Binds
  abstract fun bindAnalyticsService(
    analyticsServiceImpl: AnalyticsServiceImpl
  ): AnalyticsService
}

// If you don't own AnalyticsService.
@Module
@InstallIn(SingletonComponent::class)
object AnalyticsModule {

  @Singleton
  @Provides
  fun provideAnalyticsService(): AnalyticsService {
      return Retrofit.Builder()
               .baseUrl("https://example.com")
               .build()
               .create(AnalyticsService::class.java)
  }
}
// If AnalyticsService is an interface.
@Module
@InstallIn(SingletonComponent.class)
public abstract class AnalyticsModule {

  @Singleton
  @Binds
  public abstract AnalyticsService bindAnalyticsService(
    AnalyticsServiceImpl analyticsServiceImpl
  );
}

// If you don't own AnalyticsService.
@Module
@InstallIn(SingletonComponent.class)
public class AnalyticsModule {

  @Singleton
  @Provides
  public static AnalyticsService provideAnalyticsService() {
      return new Retrofit.Builder()
               .baseUrl("https://example.com")
               .build()
               .create(AnalyticsService.class);
  }
}

Per scoprire di più sugli ambiti dei componenti Hilt, consulta Scoping in Android and Hilt.

Gerarchia dei componenti

L'installazione di un modulo in un componente consente di accedere alle relative associazioni come dipendenza di altre associazioni nel componente o in qualsiasi componente secondario al di sotto nella gerarchia dei componenti:

ViewWithFragmentComponent si trova in FragmentComponent. Componente Frammento
    e ViewComponent si trovano in ActivityComponent. L'elemento ActivityComponent è in
    ActivityRetainedComponent. ViewModelComponent è in
    ActivityRetainedComponent. ActivityRetainedComponent e ServiceComponent
    si trovano sotto SingletonComponent.
Figura 1. Gerarchia dei componenti che Hilt generate.

Associazioni predefinite dei componenti

Ogni componente Hilt è dotato di un insieme di associazioni predefinite che Hilt può iniettare come dipendenze nelle tue associazioni personalizzate. Tieni presente che queste associazioni corrispondono all'attività generale e ai tipi di frammenti e non a sottoclassi specifiche. Questo perché Hilt utilizza una singola definizione del componente di attività per inserire tutte attività. Ogni attività ha un'istanza diversa di questo componente.

Componente Android Associazioni predefinite
SingletonComponent Application
ActivityRetainedComponent Application
ViewModelComponent SavedStateHandle
ActivityComponent Application, Activity
FragmentComponent Application, Activity e Fragment
ViewComponent Application, Activity e View
ViewWithFragmentComponent Application, Activity, Fragment, View
ServiceComponent Application, Service

Il binding del contesto dell'applicazione è disponibile anche utilizzando @ApplicationContext. Ad esempio:

KotlinJava
class AnalyticsServiceImpl @Inject constructor(
  @ApplicationContext context: Context
) : AnalyticsService { ... }

// The Application binding is available without qualifiers.
class AnalyticsServiceImpl @Inject constructor(
  application: Application
) : AnalyticsService { ... }
public class AnalyticsServiceImpl implements AnalyticsService {

  private final Context context;

  @Inject
  AnalyticsAdapter(@ApplicationContext Context context) {
    this.context = context;
  }
}

// The Application binding is available without qualifiers.
public class AnalyticsServiceImpl implements AnalyticsService {

  private final Application application;

  @Inject
  AnalyticsAdapter(Application application) {
    this.application = application;
  }
}

Il binding del contesto dell'attività è disponibile anche utilizzando @ActivityContext. Ad esempio:

KotlinJava
class AnalyticsAdapter @Inject constructor(
  @ActivityContext context: Context
) { ... }

// The Activity binding is available without qualifiers.
class AnalyticsAdapter @Inject constructor(
  activity: FragmentActivity
) { ... }
public class AnalyticsAdapter {

  private final Context context;

  @Inject
  AnalyticsAdapter(@ActivityContext Context context) {
    this.context = context;
  }
}

// The Activity binding is available without qualifiers.
public class AnalyticsAdapter {

  private final FragmentActivity activity;

  @Inject
  AnalyticsAdapter(FragmentActivity activity) {
    this.activity = activity;
  }
}

Inserisci le dipendenze in classi non supportate da Hilt

Hilt supporta i corsi Android più comuni. Tuttavia, potresti dover eseguire l'iniezione di campo nei classi non supportati da Hilt.

In questi casi, puoi creare un punto di ingresso utilizzando @EntryPoint annotazione. Un punto di ingresso è il confine tra il codice gestito da Hilt e codice che non lo è. È il punto in cui il codice entra per la prima volta nel grafico degli oggetti gestiti da Hilt. Gli entry point consentono a Hilt di utilizzare il codice utilizzato da Hilt non riescono a fornire dipendenze all'interno del grafico delle dipendenze.

Ad esempio, Hilt non supporta direttamente i contenuti. di terze parti. Se vuoi un contenuto che utilizzi Hilt e ottenere alcune dipendenze, devi definire un'interfaccia annotato con @EntryPoint per ogni tipo di associazione desiderato e includono i qualificatori. Aggiungi @InstallIn per specificare il componente in cui installare il punto di contatto come segue:

KotlinJava
class ExampleContentProvider : ContentProvider() {

  @EntryPoint
  @InstallIn(SingletonComponent::class)
  interface ExampleContentProviderEntryPoint {
    fun analyticsService(): AnalyticsService
  }

  ...
}
public class ExampleContentProvider extends ContentProvider {

  @EntryPoint
  @InstallIn(SingletonComponent.class)
  interface ExampleContentProviderEntryPoint {
    public AnalyticsService analyticsService();
  }
  ...
}

Per accedere a un punto di contatto, utilizza il metodo statico appropriato di EntryPointAccessors. Il parametro deve essere l'istanza del componente o l'oggetto @AndroidEntryPoint che funge da contenitore del componente. Assicurati che che il componente che passi come parametro e il parametro EntryPointAccessors statico corrispondono entrambi alla classe Android nell'annotazione @InstallIn nella Interfaccia @EntryPoint:

KotlinJava
class ExampleContentProvider: ContentProvider() {
    ...

  override fun query(...): Cursor {
    val appContext = context?.applicationContext ?: throw IllegalStateException()
    val hiltEntryPoint =
      EntryPointAccessors.fromApplication(appContext, ExampleContentProviderEntryPoint::class.java)

    val analyticsService = hiltEntryPoint.analyticsService()
    ...
  }
}
public class ExampleContentProvider extends ContentProvider {

  @Override
  public Cursor query(...) {
    Context appContext = getContext().getApplicationContext();
    ExampleContentProviderEntryPoint hiltEntryPoint =
      EntryPointAccessors.fromApplication(appContext, ExampleContentProviderEntryPoint.class);
    AnalyticsService analyticsService = hiltEntryPoint.analyticsService();
  }
}

In questo esempio, devi utilizzare ApplicationContext per recuperare la voce perché il punto di ingresso è installato in SingletonComponent. Se la associazione che volevi recuperare si trovasse in ActivityComponent, dovresti utilizzare ActivityContext.

Hilt and Dagger

L'elsa è costruita sulla pugnale libreria di inserimento delle dipendenze, che fornisce un modo standard per incorporare Dagger in un'applicazione Android.

Per quanto riguarda Dagger, gli obiettivi di Hilt sono i seguenti:

  • Per semplificare l'infrastruttura relativa a Dagger per le app per Android.
  • Per creare un set standard di componenti e ambiti in modo da facilitare impostazione, leggibilità e condivisione del codice tra le app.
  • Per fornire un modo semplice per eseguire il provisioning di associazioni diverse a vari tipi di build, come test, debug o release.

Poiché il sistema operativo Android crea un'istanza per molti dei suoi framework di Google, l'utilizzo di Dagger in un'app Android richiede la scrittura di del boilerplate. Hilt riduce il codice boilerplate coinvolto in usando Dagger in un'applicazione Android. Hilt genera automaticamente e fornisce quanto segue:

  • Componenti per l'integrazione delle classi di framework Android con Dagger altrimenti dovrebbero essere create a mano.
  • Annotazioni di ambito da utilizzare con i componenti generati da Hilt automaticamente.
  • Associazioni predefinite per rappresentare classi Android come Application o Activity.
  • Qualificatori predefiniti per rappresentare @ApplicationContext e @ActivityContext.

Il codice di Dagger e Hilt può coesistere nella stessa base di codice. Tuttavia, nella maggior parte dei casi è meglio usare Hilt per gestire tutto l'utilizzo di Dagger su Android. Per eseguire la migrazione di un progetto che utilizza Dagger a Hilt, consulta la guida alla migrazione e il codelab Migrazione dell'app Dagger a Hilt.

Risorse aggiuntive

Per scoprire di più su Hilt, consulta le seguenti risorse aggiuntive.

Campioni

Scopri come implementare configurazioni gestite che possono essere modificate da altre app sullo stesso dispositivo.

了解如何遵循一些最佳实践,确保您的应用在企业环境中顺畅运行。

Android's enterprise features provide organizations with a secure, flexible, and unified Android mobility platform—combining devices, applications, and management. Android apps are compatible with Android's enterprise features by default. However,

Codelab

Blog