Hilt के साथ डिपेंडेंसी इंजेक्शन

Hilt, Android के लिए डिपेंडेंसी इंजेक्शन लाइब्रेरी है. यह बॉयलरप्लेट को कम करता है जिसमें मैन्युअल डिपेंडेंसी इंजेक्शन शामिल किया गया हो. मैन्युअल डिपेंडेंसी इंजेक्शन करने के लिए, आपको हर क्लास और उसकी डिपेंडेंसी को मैन्युअल तरीके से बनाना होगा. साथ ही, डिपेंडेंसी का फिर से इस्तेमाल करने और उन्हें मैनेज करने के लिए, कंटेनर का इस्तेमाल करना होगा.

Hilt, आपके ऐप्लिकेशन में डीआई का इस्तेमाल करने का एक स्टैंडर्ड तरीका उपलब्ध कराता है. इसके लिए, यह आपके प्रोजेक्ट में मौजूद हर Android क्लास के लिए कंटेनर उपलब्ध कराता है और उनके लाइफ़साइकल को अपने-आप मैनेज करता है. Hilt को मशहूर डीआई लाइब्रेरी के ऊपर बनाया गया है डैगर: कंपाइल-टाइम में सुधार, रनटाइम की परफ़ॉर्मेंस, स्केलेबिलिटी, और Android Studio सहायता जो डैगर उपलब्ध कराता है. ज़्यादा जानकारी के लिए, खंजर और hilt देखें.

यह गाइड, Hilt और इसके जनरेट किए गए कंटेनर के बुनियादी सिद्धांतों के बारे में जानकारी देती है. यह इसमें यह जानकारी भी शामिल है कि Hilt का इस्तेमाल करने के लिए, किसी मौजूदा ऐप्लिकेशन को बूटस्ट्रैप कैसे करें.

डिपेंडेंसी जोड़ना

सबसे पहले, अपने प्रोजेक्ट के रूट में hilt-android-gradle-plugin प्लगिन जोड़ें build.gradle फ़ाइल:

ग्रूवीKotlin
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
}

इसके बाद, Gradle प्लग इन लागू करें और अपनी app/build.gradle फ़ाइल में ये डिपेंडेंसी जोड़ें:

ग्रूवी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-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, Java 8 की सुविधाओं का इस्तेमाल करता है. अपने प्रोजेक्ट में Java 8 को चालू करने के लिए, app/build.gradle फ़ाइल में ये चीज़ें जोड़ें:

ग्रूवीKotlin
android {
  ...
  compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }
}
android {
  ...
  compileOptions {
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
  }
}

Hilt ऐप्लिकेशन क्लास

Hilt का इस्तेमाल करने वाले सभी ऐप्लिकेशन में एक ऐसी Application क्लास होनी चाहिए जिसे @HiltAndroidApp के साथ एनोटेट किया गया हो.

@HiltAndroidApp, Hilt के कोड जनरेशन को ट्रिगर करता है. इसमें इसके लिए बेस क्लास भी शामिल है आपका ऐप्लिकेशन जो ऐप्लिकेशन-लेवल डिपेंडेंसी कंटेनर के रूप में काम करता है.

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

जनरेट किया गया यह Hilt कॉम्पोनेंट, Application ऑब्जेक्ट के लाइफ़साइकल से जुड़ा होता है और उसे डिपेंडेंसी देता है. इसके अलावा, यह पैरंट है का एक हिस्सा है, जिसका मतलब है कि अन्य कॉम्पोनेंट निर्भर है जो यह उपलब्ध कराता है.

Android क्लास में डिपेंडेंसी इंजेक्ट करें

एक बार Hilt को आपकी Application क्लास और ऐप्लिकेशन-लेवल में सेट अप कर दिया जाता है कॉम्पोनेंट उपलब्ध है, तो Hilt, अन्य Android क्लास के लिए डिपेंडेंसी दे सकता है जिनमें @AndroidEntryPoint एनोटेशन है:

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

फ़िलहाल, Hilt इन Android क्लास के साथ काम करता है:

  • Application (@HiltAndroidApp का इस्तेमाल करके)
  • ViewModel (@HiltViewModel का इस्तेमाल करके)
  • Activity
  • Fragment
  • View
  • Service
  • BroadcastReceiver

अगर आपको @AndroidEntryPoint की मदद से किसी Android क्लास के बारे में जानकारी देनी है, तो आपको ये काम भी करने होंगे इस पर निर्भर Android क्लास के बारे में बताती हैं. उदाहरण के लिए, अगर आपने किसी फ़्रैगमेंट पर एनोटेट किया है, तो आपको उन सभी गतिविधियों पर भी एनोटेट करना होगा जिनमें उस फ़्रैगमेंट का इस्तेमाल किया गया है.

@AndroidEntryPoint, हर Android के लिए अलग-अलग Hilt कॉम्पोनेंट जनरेट करता है क्लास की शुरुआत की है. इन कॉम्पोनेंट को, कॉम्पोनेंट के क्रम में बताए गए तरीके के मुताबिक, अपनी पैरंट क्लास से डिपेंडेंसी मिल सकती हैं.

किसी कॉम्पोनेंट से डिपेंडेंसी पाने के लिए, @Inject एनोटेशन का इस्तेमाल करें फ़ील्ड इंजेक्शन:

KotlinJava
@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() {

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

  @Inject
  AnalyticsAdapter analytics;
  ...
}

Hilt इंजेक्ट करने वाली क्लास में अन्य बेस क्लास हो सकती हैं जिनमें इंजेक्शन का भी इस्तेमाल किया जाता है. इन क्लास को @AndroidEntryPoint एनोटेशन की ज़रूरत नहीं होती है, अगर वे ऐब्सट्रैक्ट

Android क्लास को किस लाइफ़साइकल कॉलबैक में इंजेक्ट किया जाता है, इस बारे में ज़्यादा जानने के लिए, कॉम्पोनेंट लाइफ़टाइम देखें.

हिल्ट बाइंडिंग तय करें

फ़ील्ड इंजेक्शन के लिए, Hilt को यह जानने की ज़रूरत है कि यह काम करता है. बाइंडिंग में, किसी टाइप के इंस्टेंस को डिपेंडेंसी के तौर पर उपलब्ध कराने के लिए ज़रूरी जानकारी होती है.

Hilt को ज़रूरी जानकारी देने का एक तरीका कंस्ट्रक्टर इंजेक्शन है. किसी क्लास के कंस्ट्रक्टर पर @Inject एनोटेशन का इस्तेमाल करके, Hilt को बताएं कि उस क्लास के इंस्टेंस कैसे उपलब्ध कराएं:

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

  private final AnalyticsService service;

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

क्लास के एनोटेट किए गए कंस्ट्रक्टर के पैरामीटर, इसकी डिपेंडेंसी उस क्लास को शामिल न करें. उदाहरण में, AnalyticsAdapter के लिए AnalyticsService डिपेंडेंसी है. इसलिए, Hilt को AnalyticsService के इंस्टेंस उपलब्ध कराने का तरीका भी पता होना चाहिए.

हिल्ट मॉड्यूल

कभी-कभी किसी टाइप को कन्स्ट्रक्टर इंजेक्शन नहीं किया जा सकता. ऐसा कई मामलों में की वजह. उदाहरण के लिए, किसी इंटरफ़ेस को कन्स्ट्रक्टर-इंजेक्ट नहीं किया जा सकता. आपके पास ऐसे टाइप को कंस्ट्रक्टर इंजेक्ट करने का विकल्प भी नहीं है जिसका मालिकाना हक आपके पास नहीं है. जैसे, किसी बाहरी लाइब्रेरी की क्लास. ऐसे मामलों में, Hilt मॉड्यूल का इस्तेमाल करके, Hilt को बाइंडिंग की जानकारी दी जा सकती है.

Hilt मॉड्यूल एक ऐसी क्लास होती है जिसे @Module के साथ एनोटेट किया जाता है. Dagger module की तरह, यह Hilt को कुछ खास तरह के इंस्टेंस उपलब्ध कराने का तरीका बताता है. डैगर मॉड्यूल से अलग, आपको Hilt के बारे में बताने के लिए, Hilt के मॉड्यूल को @InstallIn के साथ एनोटेट करना होगा क्लास में हर मॉड्यूल का इस्तेमाल किया जाएगा या उसे इंस्टॉल किया जाएगा.

Hilt मॉड्यूल में दी जाने वाली डिपेंडेंसी, वे कॉम्पोनेंट जो उस Android क्लास से जुड़े होते हैं जिसमें आपने हिल्ट मॉड्यूल.

@Binds की मदद से इंटरफ़ेस इंस्टेंस इंजेक्ट करना

AnalyticsService उदाहरण देखें. अगर AnalyticsService एक इंटरफ़ेस है, तो आप इसे कंस्ट्रक्टर-इंजेक्ट नहीं कर सकते. इसके बजाय, Hilt को बाइंडिंग उपलब्ध कराएं @Binds के साथ एनोटेट करके एक ऐब्स्ट्रैक्ट फ़ंक्शन बनाकर जानकारी हिल्ट मॉड्यूल.

@Binds एनोटेशन से Hilt को पता चलता है कि ज़रूरत पड़ने पर किस फ़ंक्शन का इस्तेमाल करना है इंटरफ़ेस का एक इंस्टेंस दें.

व्याख्या किया गया फ़ंक्शन, Hilt को नीचे दी गई जानकारी देता है:

  • फ़ंक्शन के रिटर्न टाइप से Hilt के बारे में जानकारी मिलती है कि फ़ंक्शन कौनसा इंटरफ़ेस देता है के उदाहरण.
  • फ़ंक्शन पैरामीटर से Hilt को यह पता चलता है कि कौनसा लागू करना है.
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
  );
}

Hilt मॉड्यूल AnalyticsModule को @InstallIn(ActivityComponent.class) के साथ एनोटेट किया गया है, क्योंकि आपको Hilt को ExampleActivity में उस डिपेंडेंसी को इंजेक्ट करना है. इस एनोटेशन का मतलब है कि AnalyticsModule में डिपेंडेंसी, ऐप्लिकेशन की सभी गतिविधियों के लिए उपलब्ध है.

@Offers की मदद से इंस्टेंस इंजेक्ट करें

इंटरफ़ेस ही एकमात्र ऐसा मामला नहीं है जहां किसी टाइप को कन्स्ट्रक्टर-इंजेक्ट नहीं किया जा सकता. अगर आपके पास क्लास का मालिकाना हक नहीं है, तो कंस्ट्रक्टर इंजेक्शन भी नहीं किया जा सकता. ऐसा इसलिए होता है, क्योंकि यह किसी बाहरी लाइब्रेरी (जैसे, Retrofit, OkHttpClient या Room डेटाबेस जैसी क्लास) से मिलती है. इसके अलावा, अगर बिल्डर पैटर्न का इस्तेमाल करके इंस्टेंस बनाने ज़रूरी हैं, तो भी कंस्ट्रक्टर इंजेक्शन नहीं किया जा सकता.

ऊपर दिए गए उदाहरण पर गौर करें. अगर आपके पास सीधे तौर पर AnalyticsService क्लास का मालिकाना हक नहीं है, तो Hilt को इस टाइप के इंस्टेंस उपलब्ध कराने का तरीका बताया जा सकता है. इसके लिए, Hilt मॉड्यूल में कोई फ़ंक्शन बनाएं और उस फ़ंक्शन को @Provides के साथ एनोटेट करें.

व्याख्या किया गया फ़ंक्शन, Hilt को यह जानकारी उपलब्ध कराता है:

  • फ़ंक्शन के रिटर्न टाइप से Hilt को पता चलता है कि फ़ंक्शन किस तरह के इंस्टेंस उपलब्ध कराता है.
  • फ़ंक्शन पैरामीटर, Hilt को उस टाइप की डिपेंडेंसी के बारे में बताते हैं.
  • फ़ंक्शन का मुख्य हिस्सा, Hilt को उस टाइप का इंस्टेंस उपलब्ध कराने का तरीका बताता है. Hilt, फ़ंक्शन को हर बार कार्रवाई करने के लिए एक्ज़ीक्यूट करता है दर्ज करें.
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);
  }
}

एक ही टाइप के लिए एक से ज़्यादा बाइंडिंग उपलब्ध कराएं

ऐसे मामलों में जहां आपको Hilt की ज़रूरत है, ताकि आप उसे अलग-अलग तरीके से लागू कर सकें डिपेंडेंसी के तौर पर टाइप करें, तो आपको Hilt को एक से ज़्यादा बाइंडिंग के साथ उपलब्ध कराना होगा. आप क्वालिफ़ायर की मदद से, एक ही टाइप के लिए एक से ज़्यादा बाइंडिंग तय करें.

क्वालीफ़ायर वह जानकारी होती है जिसका इस्तेमाल किसी टाइप करें, जब उस टाइप की एक से ज़्यादा बाइंडिंग हों.

उदाहरण देखें. अगर आपको AnalyticsService पर आने वाले कॉल को इंटरसेप्ट करना है, तो इंटरसेप्टर के साथ OkHttpClient ऑब्जेक्ट का इस्तेमाल किया जा सकता है. अन्य सेवाओं के लिए, आपको कॉल को किसी दूसरे तरीके से इंटरसेप्ट करना पड़ सकता है. इसमें केस में, आपको Hilt को बताना होगा कि वे OkHttpClient.

सबसे पहले, उन क्वालिफ़ायर के बारे में बताएं जिनका इस्तेमाल आपको @Binds के बारे में बताने के लिए करना है या @Provides तरीके:

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 को यह पता होना चाहिए कि हर क्वालीफ़ायर के हिसाब से, टाइप का इंस्टेंस कैसे दिया जाए. इस मामले में, @Provides के साथ Hilt मॉड्यूल का इस्तेमाल किया जा सकता है. दोनों तरीकों का रिटर्न टाइप एक जैसा होता है, लेकिन क्वालिफ़ायर उन्हें दो अलग-अलग बाइंडिंग के तौर पर लेबल करते हैं:

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

अपनी ज़रूरत के हिसाब से कोई खास टाइप डालने के लिए, फ़ील्ड की व्याख्या करें या मिलते-जुलते क्वालीफ़ायर के साथ पैरामीटर:

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

सबसे सही तरीका यह है कि अगर किसी टाइप में क्वालीफ़ायर जोड़ा जाता है, तो की अनुमति देता है. बेस या आम को छोड़ना क्वालीफ़ायर के बिना लागू करने पर गड़बड़ी की संभावना होती है और इससे Hilt हो सकता है गलत डिपेंडेंसी डालना.

Hilt में पहले से तय किए गए क्वालिफ़ायर

Hilt, पहले से तय किए गए कुछ क्वालिफ़ायर देता है. उदाहरण के लिए, आपको ऐप्लिकेशन या गतिविधि से Context क्लास, Hilt यह जानकारी देता है @ApplicationContext और @ActivityContext क्वालिफ़ायर.

मान लें कि उदाहरण की AnalyticsAdapter क्लास को गतिविधि. यहां दिए गए कोड में, 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;
  }
}

Hilt में उपलब्ध अन्य पहले से तय बाइंडिंग के लिए, घटक डिफ़ॉल्ट देखें बाइंडिंग.

Android क्लास के लिए जनरेट किए गए कॉम्पोनेंट

हर उस Android क्लास के लिए जिसमें फ़ील्ड इंजेक्शन लिया जा सकता है, असोसिएटेड हिल्ट कॉम्पोनेंट, जिसे @InstallIn एनोटेशन में देखा जा सकता है. हर Hilt कॉम्पोनेंट, अपनी बाइंडिंग को उससे जुड़ी Android क्लास में इंजेक्ट करने के लिए ज़िम्मेदार होता है.

पिछले उदाहरणों में, Hilt में ActivityComponent के इस्तेमाल के बारे में बताया गया है मॉड्यूल देखें.

Hilt में ये कॉम्पोनेंट होते हैं:

हिलने वाला कॉम्पोनेंट Injector for
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 किसी दूसरे टाइप के लिए या फ़ील्ड इंजेक्शन के ज़रिए (जैसा कि ExampleActivity में है) AnalyticsAdapter को डिपेंडेंसी के तौर पर उपलब्ध कराता है, तो Hilt AnalyticsAdapter का एक नया इंस्टेंस उपलब्ध कराता है.

हालांकि, Hilt, बाइंडिंग को किसी खास कॉम्पोनेंट तक के दायरे में लाने की अनुमति भी देता है. Hilt, स्कोप वाली बाइंडिंग को सिर्फ़ उस कॉम्पोनेंट के हर इंस्टेंस के लिए एक बार बनाता है जिसके लिए बाइंडिंग को स्कोप किया गया है. साथ ही, उस बाइंडिंग के सभी अनुरोध एक ही इंस्टेंस शेयर करते हैं.

नीचे दी गई टेबल में, जनरेट किए गए हर कॉम्पोनेंट के लिए स्कोप एनोटेशन की सूची दी गई है:

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

उदाहरण में, अगर @ActivityScoped का इस्तेमाल करके AnalyticsAdapter को ActivityComponent के दायरे में रखा जाता है, तो Hilt उस गतिविधि के पूरे जीवनकाल में AnalyticsAdapter का एक ही इंस्टेंस उपलब्ध कराता है:

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

मान लें कि AnalyticsService की एक इंटरनल स्टेटस है, जिसके लिए हर बार एक ही इंस्टेंस का इस्तेमाल करना ज़रूरी है. ऐसा न सिर्फ़ ExampleActivity में, बल्कि ऐप्लिकेशन में कहीं भी किया जा सकता है. इस मामले में, AnalyticsService को SingletonComponent तक सीमित करना सही है. इसका मतलब है कि जब भी कॉम्पोनेंट को AnalyticsService का कोई इंस्टेंस चाहिए होता है, तो वह हर बार एक ही इंस्टेंस उपलब्ध कराता है.

इस उदाहरण में, Hilt मॉड्यूल में किसी कॉम्पोनेंट के लिए बाइंडिंग का दायरा तय करने का तरीका बताया गया है. बाइंडिंग का दायरा, उस कॉम्पोनेंट के दायरे से मेल खाना चाहिए जहां इसे इंस्टॉल किया गया है. इसलिए, इस उदाहरण में आपको ActivityComponent के बजाय SingletonComponent में AnalyticsService इंस्टॉल करना होगा:

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

Hilt कॉम्पोनेंट के स्कोप के बारे में ज़्यादा जानने के लिए, Android और Hilt में स्कोप करना लेख पढ़ें.

कॉम्पोनेंट की हैरारकी

किसी कॉम्पोनेंट में मॉड्यूल इंस्टॉल करने से, उसकी बाइंडिंग को उस कॉम्पोनेंट में मौजूद अन्य बाइंडिंग या कॉम्पोनेंट के क्रम में उसके नीचे मौजूद किसी चाइल्ड कॉम्पोनेंट की डिपेंडेंसी के तौर पर ऐक्सेस किया जा सकता है:

ViewWithFragmentComponent, FragmentComponent के तहत आता है. FragmentComponent और ViewComponent, ActivityComponent के तहत आते हैं. ऐक्टिविटीकॉम्पोनेंट इसके अंतर्गत है
    ऐक्टिविटी रीटेन्ड कॉम्पोनेंट. ViewModelcomponents है
    ऐक्टिविटी रीटेन्ड कॉम्पोनेंट. ऐक्टिविटी बरकरार रखे जाने वाले कंपोनेंट और सर्विसकॉम्पोनेंट
    सिंगलटन कॉम्पोनेंट के नीचे मौजूद हैं.
पहली इमेज. Hilt के कॉम्पोनेंट की हैरारकी जनरेट करता है.

कॉम्पोनेंट की डिफ़ॉल्ट बाइंडिंग

हर Hilt कॉम्पोनेंट में डिफ़ॉल्ट बाइंडिंग का एक सेट होता है. Hilt, इन बाइंडिंग को आपकी कस्टम बाइंडिंग में डिपेंडेंसी के तौर पर इंजेक्ट कर सकता है. ध्यान दें कि ये बाइंडिंग मेल खाती हैं सामान्य गतिविधि और फ़्रैगमेंट टाइप के साथ-साथ किसी खास सब-क्लास के लिए भी इस्तेमाल किया जा सकता है. ऐसा इसलिए है, क्योंकि 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 का इस्तेमाल करके भी ऐप्लिकेशन कॉन्टेक्स्ट बाइंडिंग उपलब्ध है. उदाहरण के लिए:

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

@ActivityContext का इस्तेमाल करके, ऐक्टिविटी कॉन्टेक्स्ट बाइंडिंग भी उपलब्ध है. इसके लिए उदाहरण:

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

Hilt के साथ काम न करने वाली क्लास में डिपेंडेंसी इंजेक्ट करना

Hilt, सबसे आम Android क्लास के साथ काम करता है. हालांकि, आपको ऐसी क्लास में फ़ील्ड इंजेक्शन लेने की ज़रूरत है जो Hilt के साथ काम नहीं करता.

ऐसे मामलों में, @EntryPoint एनोटेशन का इस्तेमाल करके एंट्री पॉइंट बनाया जा सकता है. एंट्री पॉइंट, Hilt के ज़रिए मैनेज किए जाने वाले कोड और मैनेज नहीं किए जाने वाले कोड के बीच की सीमा होती है. यह वह बिंदु है जहां कोड सबसे पहले ऐसे ऑब्जेक्ट जिन्हें Hilt मैनेज करता है. एंट्री पॉइंट, Hilt के लिए उस कोड का इस्तेमाल करने की अनुमति देते हैं जो Hilt करता है डिपेंडेंसी ग्राफ़ में डिपेंडेंसी देने के लिए मैनेज नहीं किया जा सकता.

उदाहरण के लिए, Hilt सीधे तौर पर कॉन्टेंट के साथ काम नहीं करता सेवा देने वाली कंपनियां. अगर आपको कॉन्टेंट की सेवा देने वाली कंपनी को कुछ डिपेंडेंसी पाने के लिए Hilt का इस्तेमाल करना है, तो आपको एक ऐसा इंटरफ़ेस तय करना होगा जिसे आपके पसंदीदा बाइंडिंग टाइप के लिए @EntryPoint के साथ एनोटेट किया गया हो. साथ ही, इसमें क्वालीफ़ायर शामिल करें. इसके बाद, @InstallIn जोड़ें, ताकि यह तय किया जा सके कि एंट्री पॉइंट को किस कंपोनेंट में इंस्टॉल करना है. इसके लिए, यह तरीका अपनाएं:

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

एंट्री पॉइंट को ऐक्सेस करने के लिए, EntryPointAccessors में मौजूद सही स्टैटिक तरीके का इस्तेमाल करें. पैरामीटर, कॉम्पोनेंट इंस्टेंस या @AndroidEntryPoint ऑब्जेक्ट होना चाहिए, जो कॉम्पोनेंट होल्डर के तौर पर काम करता है. पक्का करें कि पैरामीटर के तौर पर पास किया गया कॉम्पोनेंट और EntryPointAccessors स्टैटिक तरीका, दोनों @EntryPoint इंटरफ़ेस पर @InstallIn एनोटेशन में मौजूद Android क्लास से मेल खाते हों:

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

इस उदाहरण में, एंट्री पॉइंट को वापस पाने के लिए, आपको ApplicationContext का इस्तेमाल करना होगा, क्योंकि एंट्री पॉइंट SingletonComponent में इंस्टॉल है. अगर बाइंडिंग जिसे आप वापस पाना चाहते थे, वह ActivityComponent में थी, तो आप इसके बजाय ActivityContext का इस्तेमाल करें.

हिल्ट ऐंड डैगर

हिल्ट, डैगर के ऊपर बना है डिपेंडेंसी इंजेक्शन लाइब्रेरी, डैगर को शामिल करने का स्टैंडर्ड तरीका देती है Android ऐप्लिकेशन में बदल सकते हैं.

डैगर के संबंध में, Hilt के लक्ष्य इस तरह हैं:

  • Android ऐप्लिकेशन के लिए, Dagger से जुड़े इंफ़्रास्ट्रक्चर को आसान बनाना.
  • आसानी से सेटअप और आसानी से समझने के लिए, कॉम्पोनेंट और स्कोप का स्टैंडर्ड सेट बनाने के लिए, और ऐप्लिकेशन के बीच कोड शेयर करना.
  • अलग-अलग तरह के बिल्ड के लिए, अलग-अलग बाइंडिंग को आसानी से प्रोवाइड करने के लिए. जैसे, टेस्टिंग, डीबग या रिलीज़.

ऐसा इसलिए, क्योंकि Android ऑपरेटिंग सिस्टम अपने कई फ़्रेमवर्क को इंस्टैंशिएट करता है क्लास में, Android ऐप्लिकेशन में डैगर का इस्तेमाल करने से पहले, आपको बॉयलरप्लेट की मात्रा. Hilt में शामिल बॉयलरप्लेट कोड को कम कर देता है Android ऐप्लिकेशन में डैगर का इस्तेमाल करके. Hilt अपने-आप जनरेट होता है और यह जानकारी उपलब्ध कराता है:

  • डैगर के साथ Android फ़्रेमवर्क क्लास को इंटिग्रेट करने के लिए कॉम्पोनेंट नहीं तो मैन्युअल तरीके से बनाने पड़ते थे.
  • स्कोप एनोटेशन, जिनका इस्तेमाल उन कॉम्पोनेंट के साथ किया जाता है जिन्हें Hilt अपने-आप जनरेट करता है.
  • Application या Android क्लास जैसी Android क्लास को दिखाने के लिए पहले से तय बाइंडिंग Activity.
  • @ApplicationContext और @ActivityContext को दिखाने के लिए, पहले से तय किए गए क्वालिफ़ायर.

Dagger और Hilt कोड, एक ही कोडबेस में एक साथ काम कर सकते हैं. हालांकि, ज़्यादातर मामलों में, Android पर Dagger के इस्तेमाल को मैनेज करने के लिए, Hilt का इस्तेमाल करना सबसे सही होता है. माइग्रेट करने के लिए डैगर टू हिल्ट का इस्तेमाल करने वाला प्रोजेक्ट है, तो माइग्रेशन देखें गाइड और माइग्रेट करने की सुविधा Hilt के लिए आपका डैगर ऐप्लिकेशन कोडलैब (कोड बनाना सीखना).

अन्य संसाधन

Hilt के बारे में ज़्यादा जानने के लिए, नीचे दिए गए अतिरिक्त संसाधन देखें.

सैंपल

इस गाइड में, डिवाइस नीति कंट्रोलर (DPC) को डेवलप करने का तरीका बताया गया है Android एंटरप्राइज़ डिप्लॉयमेंट में डिवाइस शामिल हैं. DPC ऐप्लिकेशन, जिसे पहले इस्तेमाल किया जाता था काम करने की नीति के कंट्रोलर के तौर पर, डिवाइस से जुड़ी स्थानीय नीतियों

कोडलैब

ब्लॉग