Hilt adalah library injeksi dependensi untuk Android yang mengurangi boilerplate ketika melakukan injeksi dependensi manual dalam project Anda. Dengan melakukan injeksi dependensi manual, Anda harus membuat setiap class dan dependensinya secara manual, serta menggunakan container untuk menggunakan kembali dan mengelola dependensi.
Hilt menyediakan cara standar untuk menggunakan DI dalam aplikasi Anda dengan menyediakan container untuk setiap class Android dalam project Anda dan mengelola siklus prosesnya secara otomatis. Hilt ditambahkan pada library DI yang populer Dagger untuk mendapatkan manfaat dari ketepatan waktu kompilasi, performa runtime, skalabilitas, dan dukungan Android Studio yang disediakan oleh Dagger. Untuk informasi lebih lanjut, lihat Hilt dan Dagger.
Panduan ini menjelaskan konsep dasar Hilt dan container yang dihasilkannya. Panduan ini juga mencakup demo cara melakukan bootstrap pada aplikasi yang sudah ada untuk menggunakan Hilt.
Menambahkan dependensi
Pertama, tambahkan plugin hilt-android-gradle-plugin
ke file build.gradle
root project Anda:
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 }
Kemudian, terapkan plugin Gradle dan tambahkan dependensi ini di file
app/build.gradle
Anda:
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 menggunakan fitur Java 8. Untuk mengaktifkan Java 8 dalam
project Anda, tambahkan kode berikut ke file 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 } }
Class aplikasi Hilt
Semua aplikasi yang menggunakan Hilt harus berisi class
Application
yang dianotasi dengan
@HiltAndroidApp
.
@HiltAndroidApp
memicu pembuatan kode Hilt, termasuk class dasar untuk
aplikasi Anda yang berfungsi sebagai container dependensi tingkat aplikasi.
Kotlin
@HiltAndroidApp class ExampleApplication : Application() { ... }
Java
@HiltAndroidApp public class ExampleApplication extends Application { ... }
Komponen Hilt yang dihasilkan ini dipasang ke siklus proses
objek Application
dan menyediakan dependensi ke objek tersebut. Selain itu, komponen ini adalah komponen induk dari aplikasi, yang berarti bahwa komponen lain dapat mengakses
dependensi yang disediakannya.
Menginjeksikan dependensi ke class Android
Setelah Hilt disiapkan di class Application
Anda dan komponen
tingkat aplikasi tersedia, Hilt dapat menyediakan dependensi ke class Android lain
yang memiliki anotasi @AndroidEntryPoint
:
Kotlin
@AndroidEntryPoint class ExampleActivity : AppCompatActivity() { ... }
Java
@AndroidEntryPoint public class ExampleActivity extends AppCompatActivity { ... }
Saat ini Hilt mendukung class Android berikut:
Application
(dengan menggunakan@HiltAndroidApp
)ViewModel
(dengan menggunakan@HiltViewModel
)Activity
Fragment
View
Service
BroadcastReceiver
Jika Anda menganotasi class Android dengan @AndroidEntryPoint
, Anda juga harus
menganotasi class Android yang bergantung pada class tersebut. Misalnya, jika menganotasi sebuah
fragmen, Anda juga harus menganotasi setiap aktivitas yang menggunakan
fragmen tersebut.
@AndroidEntryPoint
menghasilkan komponen Hilt individual untuk setiap class
Android dalam project Anda. Komponen ini dapat menerima dependensi dari class induk mereka
masing-masing, seperti yang dijelaskan dalam Hierarki
komponen.
Untuk mendapatkan dependensi dari komponen, gunakan anotasi @Inject
untuk melakukan
injeksi kolom:
Kotlin
@AndroidEntryPoint class ExampleActivity : AppCompatActivity() { @Inject lateinit var analytics: AnalyticsAdapter ... }
Java
@AndroidEntryPoint public class ExampleActivity extends AppCompatActivity { @Inject AnalyticsAdapter analytics; ... }
Class yang diinjeksikan oleh Hilt dapat memiliki class dasar lainnya yang juga menggunakan injeksi.
Class tersebut tidak memerlukan anotasi @AndroidEntryPoint
jika bersifat
abstrak.
Untuk mempelajari lebih lanjut callback siklus proses tempat class Android diinjeksikan, lihat Masa aktif komponen.
Menentukan binding Hilt
Untuk melakukan injeksi kolom, Hilt perlu mengetahui cara menyediakan instance dependensi yang diperlukan dari komponen yang sesuai. Binding berisi informasi yang diperlukan untuk menyediakan instance suatu jenis sebagai dependensi.
Salah satu cara untuk memberikan informasi binding ke Hilt adalah injeksi konstruktor. Gunakan
anotasi @Inject
pada konstruktor class untuk memberi tahu Hilt cara
menyediakan instance class tersebut:
Kotlin
class AnalyticsAdapter @Inject constructor( private val service: AnalyticsService ) { ... }
Java
public class AnalyticsAdapter { private final AnalyticsService service; @Inject AnalyticsAdapter(AnalyticsService service) { this.service = service; } ... }
Parameter dari konstruktor anotasi sebuah class adalah dependensi
class tersebut. Dalam contoh ini, AnalyticsAdapter
memiliki AnalyticsService
sebagai
dependensi. Oleh karena itu, Hilt juga harus mengetahui cara menyediakan instance
AnalyticsService
.
Modul Hilt
Terkadang suatu jenis tidak dapat di-injeksikan melalui konstruktor. Hal ini dapat terjadi karena beberapa alasan. Misalnya, Anda tidak dapat menginjeksikan antarmuka melalui konstruktor. Anda juga tidak dapat menginjeksikan jenis yang tidak Anda miliki melalui konstruktor, seperti class dari library eksternal. Dalam hal ini, Anda dapat memberikan informasi binding kepada Hilt dengan menggunakan modul Hilt.
Modul Hilt adalah class yang dianotasi dengan @Module
. Seperti modul
Dagger, modul ini
memberi tahu Hilt cara menyediakan instance jenis tertentu. Tidak seperti modul Dagger,
Anda harus menganotasikan modul Hilt dengan @InstallIn
untuk memberi tahu Hilt class
Android mana yang akan digunakan atau dipasang dalam setiap modul.
Dependensi yang Anda berikan di modul Hilt tersedia di semua komponen yang dihasilkan dan dikaitkan dengan class Android tempat Anda memasang modul Hilt.
Menginjeksikan instance antarmuka dengan @Binds
Pertimbangkan contoh AnalyticsService
. Jika AnalyticsService
adalah antarmuka,
Anda tidak dapat menginjeksikannya melalui konstruktor. Sebagai gantinya, berikan informasi
binding kepada Hilt dengan cara membuat fungsi abstrak yang dianotasi dengan @Binds
di dalam
modul Hilt.
Anotasi @Binds
akan memberi tahu Hilt implementasi mana yang akan digunakan ketika Hilt harus
menyediakan instance antarmuka.
Fungsi yang dianotasi menyediakan informasi berikut kepada Hilt:
- Fungsi jenis nilai yang ditampilkan memberi tahu Hilt antarmuka mana yang instance-nya disediakan oleh fungsi.
- Parameter fungsi memberi tahu Hilt implementasi mana yang harus disediakan.
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 ); }
Modul Hilt AnalyticsModule
dianotasi dengan
@InstallIn(ActivityComponent.class)
karena Anda ingin Hilt menginjeksikan dependensi tersebut
ke ExampleActivity
. Anotasi ini berarti bahwa semua
dependensi dalam AnalyticsModule
tersedia di semua aktivitas aplikasi.
Menginjeksikan instance dengan @Provides
Antarmuka bukanlah satu-satunya kasus saat Anda tidak dapat memasukkan jenis melalui konstruktor.
Injeksi Konstruktor juga tidak dapat dilakukan jika Anda bukan pemilik class karena
class itu berasal dari library eksternal (class seperti
Retrofit,
OkHttpClient
,
atau database Room), atau jika instance harus
dibuat dengan pola
builder.
Pertimbangkan contoh sebelumnya. Jika Anda tidak secara langsung memiliki class
AnalyticsService
, Anda dapat memberi tahu Hilt cara menyediakan instance jenis ini dengan cara membuat
fungsi di dalam modul Hilt dan menganotasi fungsi itu dengan @Provides
.
Fungsi yang dianotasi menyediakan informasi berikut kepada Hilt:
- Fungsi jenis nilai yang ditampilkan memberi tahu Hilt antarmuka mana yang instance-nya disediakan oleh fungsi.
- Parameter fungsi memberi tahu Hilt dependensi dari jenis yang sesuai.
- Isi fungsi memberi tahu Hilt cara menyediakan instance dari jenis yang sesuai. Hilt menjalankan isi fungsi setiap kali harus menyediakan instance dari jenis tersebut.
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); } }
Menyediakan beberapa binding untuk jenis yang sama
Ketika Anda membutuhkan Hilt untuk menyediakan berbagai implementasi dari jenis yang sama sebagai dependensi, Anda harus memberikan beberapa binding kepada Hilt. Anda dapat menentukan beberapa binding untuk jenis yang sama dengan penentu.
Penentu adalah anotasi yang Anda gunakan agar dapat mengidentifikasi binding tertentu untuk suatu jenis ketika jenis itu memiliki beberapa binding yang telah ditetapkan.
Pertimbangkan contohnya. Jika Anda perlu meng-intercept panggilan ke AnalyticsService
, Anda
dapat menggunakan objek OkHttpClient
dengan
interceptor. Untuk
layanan lain, Anda mungkin perlu meng-intercept panggilan dengan cara lain. Dalam hal
ini, Anda perlu memberi tahu Hilt cara menyediakan dua implementasi
OkHttpClient
yang berbeda.
Pertama, tentukan penentu yang akan Anda gunakan untuk menganotasi metode @Binds
atau
@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 {}
Kemudian, Hilt perlu mengetahui cara menyediakan instance dari jenis yang sesuai
dengan setiap penentu. Dalam hal ini, Anda dapat menggunakan modul Hilt dengan @Provides
.
Kedua metode memiliki persamaan dalam jenis nilai yang ditampilkan, tetapi penentu melabelinya sebagai dua
binding yang berbeda:
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(); } }
Anda dapat menginjeksikan jenis tertentu yang dibutuhkan dengan menganotasi kolom atau parameter dengan penentu yang sesuai:
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; ... }
Sebagai praktik terbaik, jika Anda menambahkan penentu ke suatu jenis, tambahkan penentu ke semua cara yang memungkinkan untuk menyediakan dependensi tersebut. Membiarkan implementasi dasar atau umum tanpa penentu akan rawan terhadap error dan dapat menyebabkan Hilt memasukkan dependensi yang salah.
Penentu yang telah ditetapkan dalam Hilt
Hilt menyediakan beberapa penentu yang telah ditetapkan. Misalnya, karena Anda mungkin memerlukan
class Context
dari aplikasi atau aktivitas, Hilt menyediakan
penentu @ApplicationContext
dan @ActivityContext
.
Misalkan class AnalyticsAdapter
dari contoh membutuhkan konteks
aktivitas. Kode berikut menunjukkan cara menyediakan konteks
aktivitas untuk 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; } }
Untuk binding lain yang telah ditetapkan sebelumnya dan tersedia di Hilt, lihat Binding default komponen.
Komponen yang dihasilkan untuk class Android
Untuk setiap class Android tempat Anda dapat melakukan injeksi kolom, ada
komponen Hilt terkait yang dapat Anda lihat dalam anotasi @InstallIn
.
Setiap komponen Hilt bertanggung jawab untuk menginjeksikan binding ke
kelas Android yang sesuai.
Contoh sebelumnya menunjukkan penggunaan ActivityComponent
modul
dalam Hilt.
Hilt memberikan komponen berikut:
Komponen Hilt | Injektor untuk |
---|---|
SingletonComponent |
Application |
ActivityRetainedComponent |
T/A |
ViewModelComponent |
ViewModel |
ActivityComponent |
Activity |
FragmentComponent |
Fragment |
ViewComponent |
View |
ViewWithFragmentComponent |
View dianotasi dengan @WithFragmentBindings |
ServiceComponent |
Service |
Masa aktif komponen
Hilt secara otomatis membuat dan menghancurkan instance dari class komponen yang dihasilkan setelah siklus proses class Android terkait.
Komponen yang dihasilkan | Dibuat pada | Dihancurkan pada |
---|---|---|
SingletonComponent |
Application#onCreate() |
Application dihancurkan |
ActivityRetainedComponent |
Activity#onCreate() |
Activity#onDestroy() |
ViewModelComponent |
ViewModel dibuat |
ViewModel dihancurkan |
ActivityComponent |
Activity#onCreate() |
Activity#onDestroy() |
FragmentComponent |
Fragment#onAttach() |
Fragment#onDestroy() |
ViewComponent |
View#super() |
View dihancurkan |
ViewWithFragmentComponent |
View#super() |
View dihancurkan |
ServiceComponent |
Service#onCreate() |
Service#onDestroy() |
Cakupan komponen
Secara default, semua binding di Hilt adalah tanpa cakupan. Ini berarti setiap kali aplikasi Anda meminta binding, Hilt membuat instance baru dari jenis yang diperlukan.
Dalam contoh ini, setiap kali Hilt memberikan AnalyticsAdapter
sebagai dependensi ke
jenis lain atau melalui injeksi kolom (seperti di ExampleActivity
), Hilt memberikan
instance baru AnalyticsAdapter
.
Namun, Hilt juga memungkinkan binding untuk tercakup dalam komponen tertentu. Hilt hanya membuat binding cakupan sekali saja per instance dari komponen tempat binding tercakup, dan semua permintaan untuk binding itu memiliki instance yang sama.
Tabel di bawah mencantumkan anotasi cakupan untuk setiap komponen yang dihasilkan:
Class Android | Komponen yang dihasilkan | Cakupan |
---|---|---|
Application |
SingletonComponent |
@Singleton |
Activity |
ActivityRetainedComponent |
@ActivityRetainedScoped |
ViewModel |
ViewModelComponent |
@ViewModelScoped |
Activity |
ActivityComponent |
@ActivityScoped |
Fragment |
FragmentComponent |
@FragmentScoped |
View |
ViewComponent |
@ViewScoped |
View dianotasi dengan @WithFragmentBindings |
ViewWithFragmentComponent |
@ViewScoped |
Service |
ServiceComponent |
@ServiceScoped |
Dalam contoh ini, jika Anda cakupkan AnalyticsAdapter
ke ActivityComponent
menggunakan @ActivityScoped
, Hilt akan memberikan instance AnalyticsAdapter
yang sama selama masa aktif aktivitas yang terkait:
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; } ... }
Misalkan AnalyticsService
memiliki status internal yang mewajibkan instance yang sama
digunakan setiap saat—bukan hanya di ExampleActivity
, tetapi di mana saja dalam
aplikasi. Dalam hal ini, cakupan AnalyticsService
sesuai dengan
SingletonComponent
. Hasilnya, setiap kali komponen perlu
menyediakan instance AnalyticsService
, komponen akan menyediakan instance yang sama setiap
saat.
Contoh berikut menunjukkan cara mengatur cakupan binding ke komponen dalam
modul Hilt. Cakupan binding harus cocok dengan cakupan komponen tempatnya
diinstal, sehingga dalam contoh ini Anda harus menginstal AnalyticsService
di
SingletonComponent
, bukan 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); } }
Untuk mempelajari cakupan komponen Hilt lebih lanjut, lihat Cakupan di Android dan Hilt.
Hierarki komponen
Menginstal modul ke dalam komponen memungkinkan binding-nya untuk diakses sebagai dependensi binding lain dalam komponen itu atau dalam komponen turunan di bawahnya dalam hierarki komponen:
Binding default komponen
Setiap komponen Hilt dilengkapi dengan serangkaian binding default yang dapat diinjeksikan oleh Hilt sebagai dependensi ke binding kustom Anda sendiri. Perhatikan bahwa binding ini sesuai dengan aktivitas umum dan jenis fragmen, bukan dengan subclass tertentu. Ini karena Hilt menggunakan definisi komponen aktivitas tunggal untuk menginjeksikan semua aktivitas. Setiap aktivitas memiliki instance yang berbeda dari komponen ini.
Komponen Android | Binding default |
---|---|
SingletonComponent |
Application |
ActivityRetainedComponent |
Application |
ViewModelComponent |
SavedStateHandle |
ActivityComponent |
Application , Activity |
FragmentComponent |
Application , Activity , Fragment |
ViewComponent |
Application , Activity , View |
ViewWithFragmentComponent |
Application , Activity , Fragment , View |
ServiceComponent |
Application , Service |
Binding konteks aplikasi juga tersedia menggunakan @ApplicationContext
.
Contoh:
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; } }
Binding konteks aktivitas juga tersedia menggunakan @ActivityContext
. Contoh:
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; } }
Menginjeksikan dependensi dalam class yang tidak didukung oleh Hilt
Hilt dilengkapi dengan dukungan untuk class Android yang paling umum. Namun, Anda mungkin perlu melakukan injeksi kolom di kelas yang tidak didukung oleh Hilt.
Dalam kasus itu, Anda dapat membuat titik entri menggunakan anotasi
@EntryPoint
. Titik entri adalah batas antara kode yang dikelola oleh Hilt
dan yang tidak. Ini adalah titik di mana kode pertama kali masuk ke grafik
objek yang dikelola Hilt. Titik masuk memungkinkan Hilt untuk menggunakan kode yang tidak
dikelola Hilt untuk menyediakan dependensi dalam grafik dependensi.
Misalnya, Hilt tidak mendukung penyedia
konten secara langsung. Jika Anda ingin penyedia
konten menggunakan Hilt untuk mendapatkan beberapa dependensi, Anda perlu menentukan antarmuka
yang dianotasi dengan @EntryPoint
untuk setiap jenis binding yang diinginkan dan
menyertakan penentu. Lalu tambahkan @InstallIn
untuk menentukan komponen tempat
menginstal titik masuk sebagai berikut:
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(); } ... }
Untuk mengakses titik masuk, gunakan metode statis yang sesuai dari
EntryPointAccessors
. Parameter harus berupa instance komponen atau
objek @AndroidEntryPoint
yang berfungsi sebagai pemegang komponen. Pastikan
bahwa komponen yang Anda teruskan sebagai parameter dan metode
statis EntryPointAccessors
cocok dengan class Android dalam anotasi @InstallIn
pada
antarmuka @EntryPoint
:
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(); } }
Dalam contoh ini, Anda harus menggunakan ApplicationContext
untuk mengambil titik
masuk karena titik masuk diinstal di SingletonComponent
. Jika
binding yang ingin Anda ambil berada di ActivityComponent
, Anda perlu
menggunakan ActivityContext
sebagai gantinya.
Hilt dan Dagger
Hilt dibangun pada library injeksi dependensi Dagger, yang menyediakan cara standar untuk memasukkan Dagger ke aplikasi Android.
Berkaitan dengan Dagger, tujuan Hilt adalah sebagai berikut:
- Menyederhanakan infrastruktur yang berkaitan dengan Dagger untuk aplikasi Android.
- Membuat serangkaian komponen dan cakupan standar untuk memudahkan penyiapan, keterbacaan, dan berbagi kode antar-aplikasi.
- Memberikan cara yang mudah dalam menyediakan binding yang berbeda untuk berbagai jenis build, seperti pengujian, debug, atau rilis.
Karena sistem operasi Android membuat instance untuk berbagai class framework-nya sendiri, menggunakan Dagger di aplikasi Android mengharuskan Anda untuk menulis sejumlah besar boilerplate. Hilt mengurangi kode boilerplate yang terlibat dalam penggunaan Dagger pada aplikasi Android. Secara otomatis Hilt menghasilkan dan menyediakan hal berikut:
- Komponen untuk mengintegrasikan class framework Android dengan Dagger yang seharusnya Anda buat sendiri.
- Anotasi cakupan yang akan digunakan bersama komponen yang dihasilkan Hilt secara otomatis.
- Binding yang telah ditetapkan sebelumnya untuk mewakili class Android seperti
Application
atauActivity
. - Penentu yang telah ditetapkan sebelumnya untuk mewakili
@ApplicationContext
dan@ActivityContext
.
Kode Dagger dan Hilt dapat berdampingan dalam codebase yang sama. Namun, dalam sebagian besar kasus, sebaiknya gunakan Hilt untuk mengelola semua penggunaan Dagger di Android. Untuk memigrasikan project yang menggunakan Dagger ke Hilt, lihat panduan migrasi dan Memigrasikan aplikasi Dagger ke codelab Hilt.
Referensi lainnya
Untuk mempelajari Hilt lebih lanjut, lihat referensi tambahan berikut.
Contoh
Codelab
Blog
- Injeksi Dependensi pada Android dengan Hilt
- Cakupan di Android dan Hilt
- Menambahkan komponen ke hierarki Hilt
- Memigrasikan aplikasi Google I/O ke Hilt