使用 Hilt 插入依附元件

Hilt 是 Android 的依附元件插入程式庫,可減少在專案中手動插入依附元件的樣板。手動插入依附元件時,您必須手動建構每個類別及其依附元件,並透過容器,重複使用及管理依附元件。

Hilt 提供在應用程式使用 DI 的標準做法,為專案的每個 Android 類別提供容器,並自動管理其生命週期。Hilt 以熱門的 DI 程式庫 Dagger 為基礎建構而成,且具備 Dagger 提供的編譯時間正確性、執行階段效能、擴充性和 Android Studio 支援等優勢。詳情請參閱「Hilt 和 Dagger」。

本指南說明 Hilt 的基本概念及其產生的容器。並包括示範如何啟動現有應用程式,以使用 Hilt。

新增依附元件

首先,請將 hilt-android-gradle-plugin 外掛程式新增至專案的根層級 build.gradle 檔案:

Groovy

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

Kotlin

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

接著,套用 Gradle 外掛程式,並在 app/build.gradle 檔案中新增以下依附元件:

Groovy

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

Kotlin

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 使用 Java 8 功能。如要在專案中啟用 Java 8,請在 app/build.gradle 檔案中新增以下內容:

Groovy

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

Kotlin

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

Hilt 應用程式類別

使用 Hilt 的所有應用程式都必須包含以 @HiltAndroidApp 加註的 Application 類別。

@HiltAndroidApp 會觸發 Hilt 的程式碼產生器,包括做為應用程式層級依附元件容器的應用程式基礎類別。

Kotlin

@HiltAndroidApp
class ExampleApplication : Application() { ... }

Java

@HiltAndroidApp
public class ExampleApplication extends Application { ... }

產生的 Hilt 元件會附加至 Application 物件的生命週期,並為其提供依附元件。此外,因其是應用程式的父項元件,這表示其他元件可以存取其提供的依附元件。

將依附元件插入 Android 類別

Application 類別中設定 Hilt 並可供使用應用程式層級元件後,Hilt 就可為具有 @AndroidEntryPoint 註解的其他 Android 類別提供依附元件:

Kotlin

@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() { ... }

Java

@AndroidEntryPoint
public class ExampleActivity extends AppCompatActivity { ... }

Hilt 目前支援下列 Android 類別:

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

使用 @AndroidEntryPoint 為 Android 類別加上註解時,您也必須為具有依附關係的 Android 類別加上註解。例如,如果您為片段加上註解,則必須為使用該片段的任何活動加上註解。

@AndroidEntryPoint 會針對專案中的每個 Android 類別產生個別 Hilt 元件。如元件階層所述,這些元件可以從其各自的父項類別接收依附元件。

如要取得元件的依附元件,請使用 @Inject 註解來執行欄位插入:

Kotlin

@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() {

  @Inject lateinit var analytics: AnalyticsAdapter
  ...
}

Java

@AndroidEntryPoint
public class ExampleActivity extends AppCompatActivity {

  @Inject
  AnalyticsAdapter analytics;
  ...
}

Hilt 植入的類別,也可能有其他使用插入功能的基本類別。如果這些類別屬於抽象,則不需要 @AndroidEntryPoint 註解。

如要進一步瞭解 Android 類別插入哪一個生命週期回呼,請參閱「元件生命週期」。

定義 Hilt 繫結

如要執行欄位插入作業,Hilt 必須知道如何從對應的元件提供必要依附元件的執行個體。「繫結」包含提供類型執行個體做為依附元件所需的資訊。

向 Hilt 提供繫結資訊的其中一種方法是「建構函式插入」。請使用類別建構函式上的 @Inject 註解,告知 Hilt 如何提供該類別的例項:

Kotlin

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

Java

public class AnalyticsAdapter {

  private final AnalyticsService service;

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

對加上註解的類別建構函式來說,當中的參數就是該類別的依附元件。在這個範例中,AnalyticsAdapterAnalyticsService 做為依附元件。因此,Hilt 也必須瞭解如何提供 AnalyticsService 的執行個體。

Hilt 模組

有時類型無法插入建構函式。導致這種情況的原因有很多。舉例來說,您無法使用建構函式插入介面。此外,您也無法透過建構函式插入非自己擁有的類型,例如外部程式庫的類別。在這種情況下,您可以使用 Hilt 模組為 Hilt 提供繫結資訊。

Hilt 模組是加上 @Module 註解的類別。與 Dagger 模組一樣,它會指示 Hilt 如何提供特定類型的例項。與 Dagger 模組不同,您必須使用 @InstallIn 為 Hilt 模組加上註解,以告訴 Hilt 每個模組將使用或安裝的 Android 類別。

如果您在 Android 類別安裝了 Hilt 模組,則所有與該類別相關聯的已產生元件,都可使用該 Hilt 模組中提供的依附元件。

使用 @Binds 插入介面執行個體

AnalyticsService 範例為例。如果 AnalyticsService 是介面,您將無法插入建構函式。請改為在 Hilt 模組中建立 @Binds 註解的抽象函式,向 Hilt 提供繫結資訊。

@Binds 註解會說明 Hilt 在需要提供介面執行個體時要使用的實作項目。

註解函式可為 Hilt 提供下列資訊:

  • 函式回傳類型會指示 Hilt 函式提供的介面。
  • 函式參數會指示 Hilt 要提供的實作。

Kotlin

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
}

Java

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

Hilt 模組 AnalyticsModule@InstallIn(ActivityComponent.class) 加註,因為您希望 Hilt 將該依附元件插入 ExampleActivity。此註解代表 AnalyticsModule 中的所有依附元件都適用於應用程式的所有活動。

使用 @Provides 插入執行個體

介面不一定是建構函式插入類型的唯一案例。如果發生以下情況,也無法插入建構函式:您不是類別的擁有者,因為該類別是來自外部資程式庫 (例如 RetrofitOkHttpClientRoom 資料庫等類別);或者必須使用建構工具模式建立例項。

請參考上一個範例。如果您並未直接擁有 AnalyticsService 類別,可以透過在 Hilt 模組中建立函式,並使用 @Provides 為函式加上註解,向 Hilt 指明如何提供這種類型的例項。

註解函式會將以下資訊提供給 Hilt:

  • 函式傳回類型會指示 Hilt 函式應該提供給執行個體的類型。
  • 函式參數會告訴 Hilt 所對應類型的依附元件。
  • 函式主體會指示 Hilt 如何提供對應類型的例項。Hilt 會在需要提供該類型的執行個體時執行函式主體。

Kotlin

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

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

為相同類型提供多個繫結

如果您需要 Hilt 來提供與依附元件相同的不同類型實作,則必須提供多個繫結給 Hilt。您可以使用「限定詞」定義相同類型的多個繫結。

限定詞是一種註解,當類型定義了多個繫結時,您可以使用該註解來識別類型的特定繫結。

以範例為例。如果需要攔截對 AnalyticsService 的呼叫,可以將 OkHttpClient 物件與攔截器搭配使用。對於其他服務,您可能需要以不同的方式攔截呼叫。在這種情況下,您必須向 Hilt 提供兩種 OkHttpClient 的不同實作方式。

首先,請定義您要為 @Binds@Provides 方法加上註解的限定詞:

Kotlin

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

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class OtherInterceptorOkHttpClient

Java

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

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

接著,Hilt 需要瞭解如何提供與每個限定詞對應的類型執行個體。在這種情況下,您可以使用 @Provides 搭配 Hilt 模組。這兩種方法的傳回類型皆相同,但限定詞會將兩種方法分別標示為兩個不同的繫結:

Kotlin

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

Java

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

您可以為欄位或參數備註上對應的限定詞,藉此插入需要的特定類型:

Kotlin

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

Java

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

最佳做法是,如果您將限定詞加入類型,請將限定詞新增至所有提供該依附元件的方法。如果沒有在基礎或常見實作中提供限定詞,則容易出錯,且可能會導致 Hilt 插入錯誤的依附元件。

Hilt 中的預先定義限定詞

Hilt 提供部分預先定義的限定詞。例如,您可能需要應用程式或活動中的 Context 類別,因此 Hilt 提供了 @ApplicationContext@ActivityContext 限定詞。

假設範例中的 AnalyticsAdapter 類別需要活動的內容。以下程式碼示範了如何向 AnalyticsAdapter 提供活動內容:

Kotlin

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

Java

public class AnalyticsAdapter {

  private final Context context;
  private final AnalyticsService service;

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

如要瞭解 Hilt 中其他預先定義的繫結,請參閱「元件預設繫結」。

為 Android 類別產生的元件

針對可執行欄位插入的每個 Android 類別,@InstallIn 註解中都有可供參照的相關 Hilt 元件。各個 Hilt 元件會負責將其繫結插入至對應的 Android 類別。

以上範例示範如何在 Hilt 模組中使用 ActivityComponent

Hilt 提供下列元件:

Hilt 元件 注入器
SingletonComponent Application
ActivityRetainedComponent
ViewModelComponent ViewModel
ActivityComponent Activity
FragmentComponent Fragment
ViewComponent View
ViewWithFragmentComponent 附帶 @WithFragmentBindings 註解的 View
ServiceComponent Service

元件生命週期

Hilt 會根據對應 Android 類別的生命週期,自動建立並刪除產生的元件類別執行個體。

產生的元件 建立時間 刪除於
SingletonComponent Application#onCreate() Application 已刪除
ActivityRetainedComponent Activity#onCreate() Activity#onDestroy()
ViewModelComponent ViewModel 建立成功 ViewModel 已刪除
ActivityComponent Activity#onCreate() Activity#onDestroy()
FragmentComponent Fragment#onAttach() Fragment#onDestroy()
ViewComponent View#super() View 已刪除
ViewWithFragmentComponent View#super() View 已刪除
ServiceComponent Service#onCreate() Service#onDestroy()

元件範圍

根據預設,Hilt 中的所有繫結都「未限定範圍」。換句話說,每次應用程式要求繫結時,Hilt 都會針對所需類型建立新的執行個體。

在範例中,每次 Hilt 提供 AnalyticsAdapter 做為其他類型的依附元件,或透過欄位插入提供時 (如在 ExampleActivity 中),Hilt 都會提供新的 AnalyticsAdapter 執行個體。

然而,Hilt 也允許繫結限定至特定元件。Hilt 只會為每個元件例項建立一次限定範圍的繫結 (此元件即為該繫結的限定範圍),而且針對該繫結的所有要求都會共用同一例項。

下表列出每個產生元件的範圍註解:

Android 類別 產生的元件 範圍
Application SingletonComponent @Singleton
Activity ActivityRetainedComponent @ActivityRetainedScoped
ViewModel ViewModelComponent @ViewModelScoped
Activity ActivityComponent @ActivityScoped
Fragment FragmentComponent @FragmentScoped
View ViewComponent @ViewScoped
附帶 @WithFragmentBindings 註解的 View ViewWithFragmentComponent @ViewScoped
Service ServiceComponent @ServiceScoped

在範例中,如果您使用 @ActivityScopedAnalyticsAdapter 的範圍限定為 ActivityComponent,則 Hilt 會在對應活動的效期內提供同一個 AnalyticsAdapter 執行個體:

Kotlin

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

Java

@ActivityScoped
public class AnalyticsAdapter {

  private final AnalyticsService service;

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

假設 AnalyticsService 的內部狀態要求每次都使用同一例項,不僅在 ExampleActivity 中,而是在應用程式的任何位置。這個情況下就適合將 AnalyticsService 的範圍限定為 SingletonComponent。因此,當元件需要提供 AnalyticsService 的執行個體時,每次都會提供相同的執行個體。

以下範例說明如何將繫結限定範圍至 Hilt 模組中的元件。繫結範圍必須與安裝該繫結的所在元件的範圍相一致,因此在本例中,您必須將 AnalyticsService 安裝在 SingletonComponent,而非安裝在 ActivityComponent

Kotlin

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

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

如要進一步瞭解 Hilt 元件範圍,請參閱「在 Android 和 Hilt 中設定範圍」。

元件階層

將模組安裝至元件中後,其繫結即可供存取做為該元件中其他繫結的依附元件,或者做為元件階層中任何位於其下層的子元件中其他繫結的依附元件:

ViewWithFragmentComponent 位於 FragmentComponent 之下。FragmentComponent 和 ViewComponent 位於 ActivityComponent 之下。ActivityComponent 位於 ActivityRetainedComponent 之下。ViewModelComponent 位於 ActivityRetainedComponent 之下。ActivityRetainedComponent 和 ServiceComponent 位於 SingletonComponent 之下。
圖 1. Hilt 產生的元件階層。

元件預設繫結

每個 Hilt 元件都提供一組預設繫結,讓 Hilt 能夠以依附元件的形式插入自訂繫結。請注意,這些繫結對應到一般活動和片段類型,而非任何特定子類別。這是因為 Hilt 使用單一活動元件定義來插入所有活動。每個活動都有這個元件的不同執行個體。

Android 元件 預設繫結
SingletonComponent Application
ActivityRetainedComponent Application
ViewModelComponent SavedStateHandle
ActivityComponent ApplicationActivity
FragmentComponent ApplicationActivityFragment
ViewComponent ApplicationActivityView
ViewWithFragmentComponent ApplicationActivityFragmentView
ServiceComponent ApplicationService

應用程式結構定義繫結也可以使用 @ApplicationContext。例如:

Kotlin

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

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

Java

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

活動內容繫結也可以使用 @ActivityContext。舉例來說:

Kotlin

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

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

Java

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

在 Hilt 不支援的類別中插入依附元件

Hilt 提供支援最常見的 Android 類別。但是,您可能需要在 Hilt 不支援的類別中執行欄位插入。

在這種情況下,您可以使用 @EntryPoint 註解來建立進入點。進入點是 Hilt 管理程式碼和非 Hilt 管理程式碼之間的邊界。也就是程式碼首次進入 Hilt 管理的物件圖形中的點。進入點可讓 Hilt 使用非 Hilt 管理的程式碼來提供依附元件圖表中的依附元件。

舉例來說,Hilt 無法直接支援內容供應器。如果想讓內容供應器透過 Hilt 取得某些依附元件,必須為每個要使用的繫結類型定義加上 @EntryPoint 註解的介面,並加入限定詞,然後新增 @InstallIn 以指定安裝進入點的元件,如下所示:

Kotlin

class ExampleContentProvider : ContentProvider() {

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

  ...
}

Java

public class ExampleContentProvider extends ContentProvider {

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

如要存取進入點,請使用 EntryPointAccessors 提供的適當靜態方法。參數應為元件執行個體或做為元件持有者的 @AndroidEntryPoint 物件。請確認您將其做為參數傳遞的元件及 EntryPointAccessors 靜態方法都符合 @EntryPoint 介面上 @InstallIn 註解中的 Android 類別:

Kotlin

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

Java

public class ExampleContentProvider extends ContentProvider {

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

在本範例中,由於進入點會安裝在 SingletonComponent 中,因此您必須使用 ApplicationContext 擷取進入點。如果您要擷取的繫結位於 ActivityComponent 中,請改用 ActivityContext

Hilt 和 Dagger

Hilt 是以 Dagger 依附元件插入程式庫為基礎建構而成,提供將 Dagger 運用至 Android 應用程式的標準做法。

關於 Dagger,Hilt 的目標如下:

  • 簡化 Android 應用程式的 Dagger 相關基礎架構。
  • 建立在應用程式間的一組標準的元件和範圍,方便您設定、可讀性、共用代碼。
  • 提供輕鬆為各種建構類型 (例如測試、偵錯或發布) 佈建不同繫結的簡單方法。

由於 Android 作業系統會為本身的許多架構類別執行個體化,因此要在 Android 應用程式中使用 Dagger,就必須編寫大量的樣板。Hilt 會減少在 Android 應用程式中使用 Dagger 時使用的樣板程式碼。Hilt 會自動產生並提供下列資訊:

  • 整合 Android 架構類別的元件與原本必須手動建立的 Dagger。
  • 範圍註解,可與 Hilt 自動產生的元件搭配使用。
  • 預先定義的繫結,代表例如 ApplicationActivity 等 Android 類別。
  • 預先定義的限定詞,代表 @ApplicationContext@ActivityContext

Dagger 和 Hilt 程式碼可以在同一個程式碼集中共存。不過,在多數情況下,建議您使用 Hilt 來管理 Android 中所有的 Dagger 使用情形。如要將使用 Dagger 的專案遷移至 Hilt,請參閱「遷移指南」和「將 Dagger 應用程式遷移至 Hilt 程式碼研究室」。

其他資源

如要進一步瞭解 Hilt,請參閱下列其他資源:

範例

程式碼研究室

網誌