Hilt เป็นไลบรารีการแทรกทรัพยากร Dependency สำหรับ Android ที่ลด Boilerplate ของการแทรกทรัพยากร Dependency ด้วยตนเองในโปรเจ็กต์ของคุณ การใช้ทรัพยากร Dependency ด้วยตนเอง injection ต้องการให้คุณสร้าง ทุกคลาสและทรัพยากร Dependency ทั้งหมดด้วยตนเอง และเพื่อนําคอนเทนเนอร์ไปใช้ซ้ำและ จัดการการอ้างอิง
Hilt ให้วิธีมาตรฐานในการใช้ DI ในแอปพลิเคชันของคุณโดยให้ คอนเทนเนอร์ของคลาส Android ทุกคลาสในโปรเจ็กต์ รวมถึงการจัดการวงจร โดยอัตโนมัติ Hilt สร้างขึ้นจากไลบรารี DI ยอดนิยม นักวิเคราะห์เพื่อใช้ประโยชน์จาก ความถูกต้องของเวลาคอมไพล์ ประสิทธิภาพของรันไทม์ ความสามารถในการปรับขนาด และ Android Studio การสนับสนุน ที่ Dagger มอบให้ สำหรับข้อมูลเพิ่มเติม โปรดดู Hilt และ กริช
คู่มือนี้จะอธิบายแนวคิดพื้นฐานของ Hilt และคอนเทนเนอร์ที่สร้างขึ้น ทั้งนี้ ยังมีการสาธิตวิธีเปิดเครื่องแอปที่มีอยู่เพื่อใช้งาน Hilt ด้วย
การเพิ่มทรัพยากร Dependency
ก่อนอื่น ให้เพิ่มปลั๊กอิน hilt-android-gradle-plugin
ลงในรูทของโปรเจ็กต์
ไฟล์ build.gradle
:
ดึงดูด
plugins { ... id 'com.google.dagger.hilt.android' version '2.44' apply false }
Kotlin
plugins { ... id("com.google.dagger.hilt.android") version "2.44" apply false }
จากนั้นใช้ปลั๊กอิน Gradle และเพิ่มการอ้างอิงเหล่านี้ใน
app/build.gradle
ไฟล์:
ดึงดูด
... plugins { id 'kotlin-kapt' id 'com.google.dagger.hilt.android' } android { ... } dependencies { implementation "com.google.dagger:hilt-android:2.44" kapt "com.google.dagger:hilt-compiler:2.44" } // 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.44") kapt("com.google.dagger:hilt-android-compiler:2.44") } // Allow references to generated code kapt { correctErrorTypes = true }
Hilt ใช้ฟีเจอร์ของ Java 8 วิธีเปิดใช้ Java 8 in
เพิ่มค่าต่อไปนี้ลงในไฟล์ app/build.gradle
ดึงดูด
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 ต้องมีองค์ประกอบ
ชั้นเรียน Application
ที่มีคำอธิบายประกอบ
@HiltAndroidApp
@HiltAndroidApp
จะทริกเกอร์การสร้างโค้ดของ Hilt รวมถึงคลาสฐานสำหรับ
แอปพลิเคชันของคุณที่ทำหน้าที่เป็นคอนเทนเนอร์ทรัพยากร Dependency ระดับแอปพลิเคชัน
Kotlin
@HiltAndroidApp class ExampleApplication : Application() { ... }
Java
@HiltAndroidApp public class ExampleApplication extends Application { ... }
คอมโพเนนต์ Hilt ที่สร้างขึ้นนี้แนบอยู่กับออบเจ็กต์ Application
และช่วยมอบทรัพยากร Dependency ให้ นอกจากนี้ โมเดลยังอยู่ภายใต้
ซึ่งหมายความว่าคอมโพเนนต์อื่นๆ สามารถเข้าถึง
Dependency ที่มีให้
แทรกทรัพยากร Dependency ลงในคลาส Android
เมื่อตั้งค่า Hilt ในชั้นเรียน Application
และระดับแอปพลิเคชันแล้ว
คอมโพเนนต์พร้อมใช้งาน Hilt สามารถให้ทรัพยากร Dependency ไปยังคลาส Android อื่นๆ ได้
ที่มีคำอธิบายประกอบ @AndroidEntryPoint
:
Kotlin
@AndroidEntryPoint class ExampleActivity : AppCompatActivity() { ... }
Java
@AndroidEntryPoint public class ExampleActivity extends AppCompatActivity { ... }
ปัจจุบัน Hilt สนับสนุนคลาส Android ต่อไปนี้
Application
(โดยใช้@HiltAndroidApp
)ViewModel
(โดยใช้@HiltViewModel
)Activity
Fragment
View
Service
BroadcastReceiver
หากใส่คำอธิบายประกอบให้ชั้นเรียน Android ด้วย @AndroidEntryPoint
คุณจะต้อง
ใส่คำอธิบายประกอบคลาส Android ที่ต้องใช้ เช่น หากใส่คำอธิบายประกอบ
Fragment คุณต้องใส่คำอธิบายประกอบของกิจกรรมที่คุณใช้
ส่วนย่อย
@AndroidEntryPoint
สร้างคอมโพเนนต์ Hilt 1 คอมโพเนนต์สำหรับ Android แต่ละเครื่อง
ในชั้นเรียนของคุณ คอมโพเนนต์เหล่านี้จะรับทรัพยากร Dependency จาก
คลาสระดับบนที่เกี่ยวข้องตามที่อธิบายไว้ในคอมโพเนนต์
ลำดับชั้น
หากต้องการรับทรัพยากร Dependency จากคอมโพเนนต์ ให้ใช้คำอธิบายประกอบ @Inject
ในการดำเนินการ
การแทรกฟิลด์:
Kotlin
@AndroidEntryPoint class ExampleActivity : AppCompatActivity() { @Inject lateinit var analytics: AnalyticsAdapter ... }
Java
@AndroidEntryPoint public class ExampleActivity extends AppCompatActivity { @Inject AnalyticsAdapter analytics; ... }
คลาสที่ Hilt แทรกอาจมีคลาสพื้นฐานอื่นๆ ที่ใช้การแทรกด้วย
ชั้นเรียนเหล่านั้นไม่ต้องใช้คำอธิบายประกอบ @AndroidEntryPoint
หาก
ที่เป็นนามธรรม
หากต้องการดูข้อมูลเพิ่มเติมว่ามีการแทรก Callback สำหรับวงจรการใช้งานที่มีการแทรกคลาส Android เข้ามา ดูอายุการใช้งานของคอมโพเนนต์
กำหนดการเชื่อมโยง Hilt
ในการดำเนินการแทรกฟิลด์ Hilt จำเป็นต้องทราบวิธีระบุอินสแตนซ์ของ ทรัพยากร Dependency ที่จำเป็นจากคอมโพเนนต์ที่เกี่ยวข้อง การเชื่อมโยงประกอบด้วย ข้อมูลที่จำเป็นต่อการระบุอินสแตนซ์ของประเภทเป็นทรัพยากร Dependency
วิธีหนึ่งในการให้ข้อมูลการเชื่อมโยงกับ 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; } ... }
พารามิเตอร์ของตัวสร้างที่มีคำอธิบายประกอบของคลาสคือทรัพยากร Dependency ของ
ชั้นเรียนนั้น ในตัวอย่างนี้ AnalyticsAdapter
มี AnalyticsService
เป็น
การพึ่งพา ด้วยเหตุนี้ Hilt จึงต้องรู้วิธีแสดงตัวอย่าง
AnalyticsService
โมดูล Hilt
บางครั้งไม่สามารถแทรกประเภทตัวสร้าง กรณีนี้อาจเกิดขึ้นได้กับ เหตุผล เช่น คุณไม่สามารถสร้างอินเทอร์เฟซได้ และคุณยัง ไม่สามารถแทรกประเภทที่คุณไม่ได้เป็นเจ้าของ เช่น คลาสจาก ไลบรารีภายนอก ในกรณีเหล่านี้ คุณสามารถระบุข้อมูลการเชื่อมโยงของ Hilt ได้ ได้โดยใช้โมดูล Hit
โมดูล Hilt เป็นคลาสที่มีการใส่คำอธิบายประกอบเป็น @Module
เหมือนกัญชา
โมดูล
บอก Hilt ถึงวิธีแสดงอินสแตนซ์บางประเภท ซึ่งแตกต่างจากโมดูล Dagger
คุณต้องใส่คำอธิบายประกอบให้กับโมดูล Hilt ด้วย @InstallIn
เพื่อบอก Hilt ว่า Android
แต่ละโมดูลจะถูกใช้หรือติดตั้ง
ทรัพยากร Dependency ที่คุณระบุในโมดูล Hilt จะมีอยู่ในทุกรายการที่สร้างขึ้น ที่เกี่ยวข้องกับคลาส Android ที่คุณติดตั้ง โมดูล 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
หมายเหตุนี้หมายความว่า
ทรัพยากร Dependency ใน AnalyticsModule
มีอยู่ในกิจกรรมทั้งหมดของแอป
แทรกอินสแตนซ์ด้วย @Provides
อินเทอร์เฟซไม่ได้เป็นเพียงกรณีเดียวที่คุณไม่สามารถสร้างการแทรกประเภท
การแทรกตัวสร้างเป็นไปไม่ได้เช่นกัน หากคุณไม่ใช่เจ้าของชั้นเรียนเนื่องจาก
มาจากไลบรารีภายนอก (ชั้นเรียนต่างๆ เช่น
การปรับปรุง
OkHttpClient
หรือฐานข้อมูลห้อง) หรือหากอินสแตนซ์ต้อง
สร้างขึ้นด้วยเครื่องมือสร้าง
รูปแบบ
ลองดูตัวอย่างก่อนหน้านี้ หากคุณไม่ได้เป็นเจ้าของ AnalyticsService
โดยตรง
คุณสามารถบอก Hilt ถึงวิธีจัดเตรียมอินสแตนซ์ประเภทนี้โดยสร้าง
ภายในโมดูล Hilt และใส่คำอธิบายประกอบฟังก์ชันนั้นด้วย @Provides
ฟังก์ชันที่มีคำอธิบายประกอบจะให้ข้อมูลต่อไปนี้แก่ Hilt
- ประเภทการแสดงผลฟังก์ชันจะบอก Hilt ว่าฟังก์ชันแสดงอินสแตนซ์ประเภทใด
- พารามิเตอร์ฟังก์ชันจะบอก Hilt ถึงทรัพยากร Dependency ของประเภทที่เกี่ยวข้อง
- ส่วนเนื้อหาของฟังก์ชันจะบอก 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
ที่มี
Interceptor สำหรับ
ให้บริการอื่นๆ คุณอาจจะต้อง
ดักฟังการโทรด้วยวิธีอื่นๆ ในนั้น
คุณต้องบอก Hilt ถึงวิธีการติดตั้งใช้งาน 2 ประเภท
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 ต้องการทราบวิธีระบุอินสแตนซ์ของประเภทที่ตรงกับ
กับตัวระบุแต่ละรายการ ในกรณีนี้ คุณใช้โมดูล Hilt กับ @Provides
ได้
ทั้ง 2 วิธีมีประเภทการแสดงผลเหมือนกัน แต่ตัวระบุจะติดป้ายกำกับว่าเป็น 2
การเชื่อมโยงต่างๆ กัน:
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; ... }
แนวทางปฏิบัติแนะนำคือหากคุณเพิ่มคำขยายในประเภท ให้เพิ่มคำขยายในประเภท วิธีต่างๆ ที่เป็นไปได้ในการให้ทรัพยากร Dependency นั้น ออกจากฐานทัพหรือ การใช้งานโดยไม่มีตัวระบุจะเกิดข้อผิดพลาดได้ง่ายและอาจทำให้เกิด Hilt กำลังแทรกทรัพยากร Dependency ที่ไม่ถูกต้อง
ตัวระบุที่กำหนดไว้ล่วงหน้าใน 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 แต่ละคลาสที่คุณสามารถแทรกข้อมูลภาคสนามได้ จะมี
คอมโพเนนต์ Hilt ที่เกี่ยวข้องซึ่งคุณอ้างถึงในคำอธิบายประกอบ @InstallIn
ได้
คอมโพเนนต์ Hilt แต่ละคอมโพเนนต์ทำหน้าที่แทรกการเชื่อมโยงของตนลงใน
คลาส Android ที่เกี่ยวข้อง
ตัวอย่างก่อนหน้านี้แสดงการใช้ ActivityComponent
ในภาษาฮิลต์
โมดูล
Hilt มีคอมโพเนนต์ดังต่อไปนี้
คอมโพเนนต์ Hilt | หัวฉีดสำหรับ |
---|---|
SingletonComponent |
Application |
ActivityRetainedComponent |
ไม่มี |
ViewModelComponent |
ViewModel |
ActivityComponent |
Activity |
FragmentComponent |
Fragment |
ViewComponent |
View |
ViewWithFragmentComponent |
View มีคำอธิบายประกอบ @WithFragmentBindings |
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
เป็นทรัพยากร Dependency
ประเภทอื่นหรือผ่านการแทรกช่อง (เช่น ExampleActivity
) Hilt จะให้
อินสแตนซ์ใหม่ของ AnalyticsAdapter
อย่างไรก็ตาม Hilt ยังอนุญาตให้กำหนดขอบเขตการเชื่อมโยงไปยังคอมโพเนนต์ที่เฉพาะเจาะจงได้ด้วย ฮิลต์ จะสร้างการเชื่อมโยงที่กำหนดขอบเขตเพียง 1 ครั้งต่ออินสแตนซ์ของคอมโพเนนต์ที่ ขอบเขตของการผูกข้อมูลจะจำกัดอยู่ และคำขอทั้งหมดสำหรับการเชื่อมโยงนั้นจะใช้อินสแตนซ์เดียวกัน
ตารางด้านล่างแสดงรายการคำอธิบายประกอบขอบเขตสำหรับคอมโพเนนต์ที่สร้างขึ้นแต่ละรายการ
คลาส Android | คอมโพเนนต์ที่สร้างขึ้น | ขอบเขต |
---|---|---|
Application |
SingletonComponent |
@Singleton |
Activity |
ActivityRetainedComponent |
@ActivityRetainedScoped |
ViewModel |
ViewModelComponent |
@ViewModelScoped |
Activity |
ActivityComponent |
@ActivityScoped |
Fragment |
FragmentComponent |
@FragmentScoped |
View |
ViewComponent |
@ViewScoped |
View มีคำอธิบายประกอบ @WithFragmentBindings |
ViewWithFragmentComponent |
@ViewScoped |
Service |
ServiceComponent |
@ServiceScoped |
ในตัวอย่างนี้ หากคุณกำหนดขอบเขต AnalyticsAdapter
เป็น ActivityComponent
โดยใช้ @ActivityScoped
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
ลำดับชั้นขององค์ประกอบ
การติดตั้งโมดูลลงในคอมโพเนนต์อนุญาตให้เข้าถึงการเชื่อมโยงของโมดูลดังกล่าวเป็น การพึ่งพาการเชื่อมโยงอื่นๆ ในคอมโพเนนต์นั้นหรือในคอมโพเนนต์ย่อยใดๆ ด้านล่าง ในลำดับชั้นขององค์ประกอบ
การเชื่อมโยงเริ่มต้นของคอมโพเนนต์
คอมโพเนนต์ Hilt แต่ละรายการมาพร้อมกับชุดการเชื่อมโยงเริ่มต้นที่ Hilt สามารถแทรกได้ Dependency ลงในการเชื่อมโยงที่คุณกำหนดเอง โปรดทราบว่าการเชื่อมโยงเหล่านี้จะสอดคล้องกับ กิจกรรมทั่วไปและประเภทส่วนย่อย ไม่ใช่คลาสย่อยที่เฉพาะเจาะจงใดๆ นั่นเป็นเพราะ Hilt ใช้คำจำกัดความคอมโพเนนต์กิจกรรมเดี่ยวเพื่อแทรกทั้งหมด กิจกรรม แต่ละกิจกรรมจะมีอินสแตนซ์ที่แตกต่างกันของคอมโพเนนต์
คอมโพเนนต์ Android | การเชื่อมโยงเริ่มต้น |
---|---|
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 |
การเชื่อมโยงบริบทแอปพลิเคชันยังใช้งานผ่าน @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; } }
แทรกทรัพยากร Dependency ในชั้นเรียนที่ Hilt ไม่รองรับ
Hilt มาพร้อมการรองรับชั้นเรียน Android ที่พบบ่อยที่สุด อย่างไรก็ตาม คุณอาจ จำเป็นต้องแทรกข้อมูลภาคสนามในชั้นเรียนที่ Hilt ไม่รองรับ
ในกรณีเหล่านั้น คุณสามารถสร้างจุดแรกเข้าโดยใช้ @EntryPoint
หมายเหตุ จุดแรกเข้าคือขอบเขตระหว่างโค้ดที่จัดการโดย Hilt
และโค้ดที่ไม่เกี่ยวข้อง ซึ่งเป็นจุดที่โค้ดจะป้อนลงในกราฟของ
ที่ Hilt จัดการ จุดแรกเข้าช่วยให้ Hilt สามารถใช้โค้ดที่ Hilt ทำ
ไม่สามารถระบุทรัพยากร Dependency ภายในกราฟทรัพยากร Dependency ได้
ตัวอย่างเช่น 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
แบบคงที่
ทั้ง 2 วิธีนี้ตรงกับคลาส Android ในคำอธิบายประกอบ @InstallIn
ใน
อินเทอร์เฟซ @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(); } }
ในตัวอย่างนี้ คุณต้องใช้ ApplicationContext
เพื่อเรียกข้อมูลรายการ
เนื่องจากจุดแรกเข้าได้รับการติดตั้งใน SingletonComponent
หาก
การเชื่อมโยงที่คุณต้องการดึงข้อมูลนั้นอยู่ใน ActivityComponent
คุณจะ
ให้ใช้ ActivityContext
แทน
ฮิลต์และกริช
Hilt สร้างโดยมี Dagger ไลบรารี Dependency Injection ที่มีวิธีมาตรฐานในการรวม Dagger ในแอปพลิเคชัน Android
ในส่วนของ Dagger เป้าหมายของ Hilt มีดังนี้:
- เพื่อลดความซับซ้อนของโครงสร้างพื้นฐานที่เกี่ยวข้องกับ Dagger สำหรับแอป Android
- ในการสร้างชุดคอมโพเนนต์และขอบเขตมาตรฐานเพื่อให้ง่ายต่อการตั้งค่า ความสะดวกในการอ่าน และการแชร์โค้ดระหว่างแอป
- เพื่อมอบวิธีง่ายๆ ในการจัดสรรการเชื่อมโยงต่างๆ กับบิลด์ประเภทต่างๆ เช่น การทดสอบ การแก้ไขข้อบกพร่อง หรือรุ่น
เนื่องจากระบบปฏิบัติการ Android มีการสร้างอินสแตนซ์หลายรายการของตัวเอง เมื่อใช้ Dagger ในแอป Android คุณจะต้องเขียน และเทมเพลตต้นแบบ Hilt จะลดโค้ดสำเร็จรูปที่เกี่ยวข้องใน ใช้ Dagger ในแอปพลิเคชัน Android Hilt จะสร้างและ มอบสิ่งต่อไปนี้
- คอมโพเนนต์สำหรับการผสานรวมคลาสเฟรมเวิร์ก Android กับ Dagger ที่คุณ แต่เป็นการสร้างด้วยตนเอง
- คำอธิบายประกอบขอบเขตเพื่อใช้กับคอมโพเนนต์ที่ Hilt สร้างขึ้น โดยอัตโนมัติ
- การเชื่อมโยงที่กำหนดไว้ล่วงหน้าเพื่อแสดงคลาส Android เช่น
Application
หรือActivity
- ตัวระบุที่กำหนดไว้ล่วงหน้าสำหรับแสดงถึง
@ApplicationContext
และ@ActivityContext
โค้ด Dagger และ Hilt สามารถอยู่ร่วมกันในฐานของโค้ดเดียวกันได้ แต่ในกรณีส่วนใหญ่ คือวิธีที่ดีที่สุดในการใช้ Hilt เพื่อจัดการการใช้งาน Dagger ทั้งหมดใน Android วิธีย้ายข้อมูล โครงการที่ใช้ Dagger to Hilt โปรดดูการย้ายข้อมูล คู่มือและการย้ายข้อมูล แอป Dagger เพื่อ Hilt Codelab
แหล่งข้อมูลเพิ่มเติม
หากต้องการดูข้อมูลเพิ่มเติมเกี่ยวกับ Hilt โปรดดูแหล่งข้อมูลเพิ่มเติมต่อไปนี้
ตัวอย่าง
Codelab
บล็อก
- การแทรกทรัพยากร Dependency ใน Android ด้วย ฮิลต์
- การจำกัดขอบเขตใน Android และ ฮิลต์
- การเพิ่มคอมโพเนนต์ลงใน Hilt ลำดับชั้น
- การย้ายข้อมูลแอป Google I/O ไปยัง ฮิลต์