تزریق وابستگی با هیلت

Hilt یک کتابخانه تزریق وابستگی برای اندروید است که حجم کارهای تکراری و خسته‌کننده‌ی تزریق وابستگی دستی در پروژه را کاهش می‌دهد. انجام تزریق وابستگی دستی مستلزم آن است که شما هر کلاس و وابستگی‌های آن را به صورت دستی بسازید و از کانتینرها برای استفاده مجدد و مدیریت وابستگی‌ها استفاده کنید.

Hilt با ارائه کانتینرهایی برای هر کلاس اندروید در پروژه شما و مدیریت خودکار چرخه حیات آنها، روشی استاندارد برای استفاده از DI در برنامه شما ارائه می‌دهد. Hilt بر اساس کتابخانه DI محبوب Dagger ساخته شده است تا از صحت زمان کامپایل، عملکرد زمان اجرا، مقیاس‌پذیری و پشتیبانی Android Studio که Dagger ارائه می‌دهد، بهره‌مند شود. برای اطلاعات بیشتر، به Hilt و Dagger مراجعه کنید.

این راهنما مفاهیم اولیه Hilt و کانتینرهای تولید شده توسط آن را توضیح می‌دهد. همچنین شامل نمایشی از نحوه بوت‌استرپ کردن یک برنامه موجود برای استفاده از Hilt است.

افزودن وابستگی‌ها

ابتدا، افزونه hilt-android-gradle-plugin را به فایل build.gradle ریشه پروژه خود اضافه کنید:

کاتلین

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

گرووی

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

سپس، افزونه Gradle را اعمال کنید و این وابستگی‌ها را در فایل app/build.gradle خود اضافه کنید:

کاتلین

plugins {
  id("com.google.devtools.ksp")
  id("com.google.dagger.hilt.android")
}

android {
  ...
}

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

گرووی

...
plugins {
  id 'com.google.devtools.ksp'
  id 'com.google.dagger.hilt.android'
}

android {
  ...
}

dependencies {
  implementation "com.google.dagger:hilt-android:2.57.1"
  ksp "com.google.dagger:hilt-compiler:2.57.1"
}

برای اطمینان از اینکه پروژه شما برای جاوا ۱۷ پیکربندی شده است، که توسط نسخه‌های Jetpack Compose و Hilt مورد نیاز است، موارد زیر را به فایل app/build.gradle اضافه کنید:

کاتلین

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

گرووی

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

کلاس کاربرد هیلت

تمام برنامه‌هایی که از Hilt استفاده می‌کنند باید شامل یک کلاس Application باشند که با @HiltAndroidApp حاشیه‌نویسی شده باشد.

@HiltAndroidApp تولید کد Hilt را آغاز می‌کند، که شامل یک کلاس پایه برای برنامه شما است که به عنوان ظرف وابستگی سطح برنامه عمل می‌کند.

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

این کامپوننت Hilt تولید شده به چرخه حیات شیء Application متصل شده و وابستگی‌هایی را برای آن فراهم می‌کند. علاوه بر این، کامپوننت والد برنامه است، به این معنی که سایر کامپوننت‌ها می‌توانند به وابستگی‌هایی که ارائه می‌دهد دسترسی داشته باشند.

تزریق وابستگی‌ها به کلاس‌های اندروید

زمانی که Hilt در کلاس Application شما تنظیم شد و یک کامپوننت سطح Application در دسترس قرار گرفت، Hilt می‌تواند وابستگی‌هایی را برای سایر کلاس‌های اندروید که حاشیه‌نویسی @AndroidEntryPoint را دارند، فراهم کند:

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

Hilt در حال حاضر از کلاس‌های اندروید زیر پشتیبانی می‌کند:

  • Application (با استفاده از @HiltAndroidApp )
  • ViewModel (با استفاده از @HiltViewModel )
  • Activity
  • Service
  • BroadcastReceiver

در Compose، نیازی به حاشیه‌نویسی تک تک Composableها ندارید. در عوض، می‌توانید ComponentActivity ریشه خود را با @AndroidEntryPoint حاشیه‌نویسی کنید. این به عنوان نقطه ورود DI واحد برای کل سلسله مراتب رابط کاربری شما عمل می‌کند، بنابراین می‌توانید مستقیماً درون توابع Composable خود به ViewModelهای Hilt-injected دسترسی داشته باشید.

@AndroidEntryPoint برای هر کلاس اندروید در پروژه شما یک کامپوننت Hilt جداگانه تولید می‌کند. این کامپوننت‌ها می‌توانند از کلاس‌های والد مربوطه خود، همانطور که در سلسله مراتب کامپوننت توضیح داده شده است، وابستگی دریافت کنند.

برای دریافت وابستگی‌ها از یک کامپوننت، از حاشیه‌نویسی @Inject برای انجام تزریق فیلد استفاده کنید:

@AndroidEntryPoint
class ExampleActivity : ComponentActivity() {

  @Inject lateinit var analytics: AnalyticsAdapter
  ...
}

کلاس‌هایی که Hilt تزریق می‌کند می‌توانند کلاس‌های پایه دیگری داشته باشند که آنها هم از تزریق استفاده می‌کنند. اگر این کلاس‌ها انتزاعی باشند، نیازی به حاشیه‌نویسی @AndroidEntryPoint ندارند.

برای کسب اطلاعات بیشتر در مورد اینکه یک کلاس اندروید در کدام چرخه عمر فراخوانی تزریق می‌شود، به بخش طول عمر کامپوننت‌ها مراجعه کنید.

تعریف اتصالات Hilt

برای انجام تزریق فیلد، هیلت باید بداند که چگونه نمونه‌هایی از وابستگی‌های لازم را از مؤلفه مربوطه ارائه دهد. یک اتصال شامل اطلاعات لازم برای ارائه نمونه‌هایی از یک نوع به عنوان وابستگی است.

یکی از راه‌های ارائه اطلاعات اتصال به Hilt، تزریق سازنده است. از حاشیه‌نویسی @Inject روی سازنده یک کلاس استفاده کنید تا به Hilt بگویید چگونه نمونه‌هایی از آن کلاس را ارائه دهد:

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

پارامترهای یک سازنده‌ی حاشیه‌نویسی‌شده‌ی یک کلاس، وابستگی‌های آن کلاس هستند. در این مثال، AnalyticsAdapter دارای AnalyticsService به عنوان یک وابستگی است. بنابراین، Hilt باید بداند که چگونه نمونه‌هایی از AnalyticsService را نیز ارائه دهد.

ماژول‌های دسته

گاهی اوقات نمی‌توان یک نوع را با تزریق سازنده (Constructor-injected) اجرا کرد. این اتفاق می‌تواند به دلایل مختلفی رخ دهد. برای مثال، شما نمی‌توانید یک رابط را با تزریق سازنده (Constructor-injected) اجرا کنید. همچنین نمی‌توانید نوعی را که متعلق به شما نیست، مانند کلاسی از یک کتابخانه خارجی، با تزریق سازنده (Constructor-injected) اجرا کنید. در این موارد، می‌توانید با استفاده از ماژول‌های Hilt ، اطلاعات اتصال را در اختیار Hilt قرار دهید.

یک ماژول Hilt کلاسی است که با @Module حاشیه‌نویسی شده است. این ماژول به Hilt دستورالعمل‌هایی در مورد نحوه ایجاد نمونه‌هایی از انواعی که نمی‌توان از طریق تزریق سازنده ارائه داد، مانند رابط‌ها یا کلاس‌های شخص ثالث، ارائه می‌دهد. همچنین باید هر ماژول را با @InstallIn حاشیه‌نویسی کنید تا به Hilt بگویید که هر ماژول در کدام کلاس اندروید استفاده یا نصب خواهد شد.

وابستگی‌هایی که در ماژول‌های Hilt ارائه می‌دهید، در تمام کامپوننت‌های تولید شده‌ای که با کلاس اندروید مرتبط هستند و ماژول Hilt را در آن نصب می‌کنید، در دسترس هستند.

تزریق نمونه‌های رابط با @Binds

مثال AnalyticsService را در نظر بگیرید. اگر AnalyticsService یک رابط باشد، نمی‌توانید آن را با استفاده از constructor-inject تزریق کنید. در عوض، با ایجاد یک تابع انتزاعی که با @Binds درون یک ماژول Hilt حاشیه‌نویسی شده است، اطلاعات اتصال را در اختیار Hilt قرار دهید.

حاشیه‌نویسی @Binds به Hilt می‌گوید که در صورت نیاز به ارائه نمونه‌ای از یک رابط، از کدام پیاده‌سازی استفاده کند.

تابع حاشیه‌نویسی‌شده اطلاعات زیر را در اختیار Hilt قرار می‌دهد:

  • نوع بازگشتی تابع به Hilt می‌گوید که تابع نمونه‌هایی از چه رابطی را ارائه می‌دهد.
  • پارامتر تابع به Hilt می‌گوید که کدام پیاده‌سازی را ارائه دهد.
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
}

ماژول Hilt به نام AnalyticsModule با @InstallIn(ActivityComponent.class) حاشیه‌نویسی شده است، زیرا شما می‌خواهید Hilt آن وابستگی را به ExampleActivity تزریق کند. این حاشیه‌نویسی به این معنی است که تمام وابستگی‌های موجود در AnalyticsModule در تمام فعالیت‌های برنامه در دسترس هستند.

تزریق نمونه‌ها با @Provides

رابط‌ها تنها مواردی نیستند که نمی‌توانید یک نوع را با استفاده از سازنده تزریق کنید. تزریق سازنده همچنین در صورتی که مالک کلاس نباشید، به این دلیل که از یک کتابخانه خارجی (کلاس‌هایی مانند Retrofit ، OkHttpClient یا پایگاه‌های داده Room ) آمده است، یا اگر نمونه‌هایی باید با الگوی سازنده ایجاد شوند، امکان‌پذیر نیست.

مثال قبلی را در نظر بگیرید. اگر مستقیماً مالک کلاس AnalyticsService نیستید، می‌توانید با ایجاد یک تابع درون ماژول Hilt و حاشیه‌نویسی آن تابع با @Provides ، به Hilt بگویید که چگونه نمونه‌هایی از این نوع را ارائه دهد.

تابع حاشیه‌نویسی‌شده اطلاعات زیر را در اختیار هیلت قرار می‌دهد:

  • نوع بازگشتی تابع به Hilt می‌گوید که تابع نمونه‌هایی از چه نوعی را ارائه می‌دهد.
  • پارامترهای تابع، وابستگی‌های نوع مربوطه را به Hilt اطلاع می‌دهند.
  • بدنه تابع به Hilt می‌گوید که چگونه یک نمونه از نوع مربوطه را ارائه دهد. Hilt هر بار که نیاز به ارائه نمونه‌ای از آن نوع داشته باشد، بدنه تابع را اجرا می‌کند.
@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)
  }
}

ارائه چندین اتصال برای یک نوع داده

در مواردی که نیاز دارید Hilt پیاده‌سازی‌های مختلفی از یک نوع وابستگی ارائه دهد، باید چندین اتصال به Hilt ارائه دهید. می‌توانید چندین اتصال را برای یک نوع با استفاده از qualifierها تعریف کنید.

یک توصیف‌کننده (qualifier) ​​حاشیه‌نویسی‌ای است که برای شناسایی یک متغیر خاص برای یک نوع، زمانی که آن نوع چندین متغیر تعریف شده دارد، استفاده می‌کنید.

به این مثال توجه کنید. اگر نیاز به رهگیری فراخوانی‌ها به AnalyticsService دارید، می‌توانید از یک شیء OkHttpClient به همراه یک interceptor استفاده کنید. برای سایر سرویس‌ها، ممکن است نیاز به رهگیری فراخوانی‌ها به روش دیگری داشته باشید. در این صورت، باید به Hilt بگویید که چگونه دو پیاده‌سازی مختلف از OkHttpClient را ارائه دهد.

ابتدا، توصیف‌گرهایی را که برای حاشیه‌نویسی متدهای @Binds یا @Provides استفاده خواهید کرد، تعریف کنید:

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

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

سپس، Hilt باید بداند که چگونه یک نمونه از نوعی که با هر توصیف‌کننده مطابقت دارد، ارائه دهد. در این حالت، می‌توانید از یک ماژول Hilt با @Provides استفاده کنید. هر دو متد نوع بازگشتی یکسانی دارند، اما توصیف‌کننده‌ها آنها را به عنوان دو متغیر متفاوت برچسب‌گذاری می‌کنند:

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

شما می‌توانید نوع خاصی را که نیاز دارید با حاشیه‌نویسی فیلد یا پارامتر با توصیف‌کننده‌ی مربوطه تزریق کنید:

// 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: ComponentActivity() {

  @AuthInterceptorOkHttpClient
  @Inject lateinit var okHttpClient: OkHttpClient
}

به عنوان یک روش برتر، اگر یک توصیف‌کننده به یک نوع اضافه می‌کنید، توصیف‌کننده‌ها را به تمام روش‌های ممکن برای ارائه آن وابستگی اضافه کنید. رها کردن پیاده‌سازی پایه یا مشترک بدون توصیف‌کننده، مستعد خطا است و می‌تواند منجر به تزریق وابستگی اشتباه توسط Hilt شود.

توصیف‌کننده‌های از پیش تعریف‌شده در Hilt

Hilt برخی توصیف‌کننده‌های از پیش تعریف‌شده را ارائه می‌دهد. برای مثال، از آنجایی که ممکن است به کلاس Context از برنامه یا فعالیت نیاز داشته باشید، Hilt توصیف‌کننده‌های @ApplicationContext و @ActivityContext را ارائه می‌دهد.

فرض کنید کلاس AnalyticsAdapter از مثال به context مربوط به activity نیاز دارد. کد زیر نحوه ارائه activity context به AnalyticsAdapter را نشان می‌دهد:

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

برای سایر اتصالات از پیش تعریف شده موجود در Hilt، به اتصالات پیش‌فرض کامپوننت مراجعه کنید.

کامپوننت‌های تولید شده برای کلاس‌های اندروید

برای هر کلاس اندروید که می‌توانید در آن تزریق فیلد انجام دهید، یک کامپوننت Hilt مرتبط وجود دارد که می‌توانید در حاشیه‌نویسی @InstallIn به آن اشاره کنید. هر کامپوننت Hilt مسئول تزریق متغیرهای خود به کلاس اندروید مربوطه است.

مثال‌های قبلی استفاده از ActivityComponent را در ماژول‌های Hilt نشان دادند.

هیلت اجزای زیر را ارائه می‌دهد:

جزء دسته انژکتور برای
SingletonComponent Application
ActivityRetainedComponent ناموجود
ViewModelComponent ViewModel
ActivityComponent Activity
ServiceComponent Service

طول عمر قطعات

هیلت به طور خودکار نمونه‌هایی از کلاس‌های کامپوننت تولید شده را با پیروی از چرخه حیات کلاس‌های اندروید مربوطه ایجاد و از بین می‌برد.

مولفه تولید شده ایجاد شده در تخریب شده در
SingletonComponent Application#onCreate() Application از بین رفت
ActivityRetainedComponent Activity#onCreate() Activity#onDestroy()
ViewModelComponent ViewModel ایجاد شد ViewModel از بین رفت
ActivityComponent Activity#onCreate() Activity#onDestroy()
ServiceComponent Service#onCreate() Service#onDestroy()

دامنه‌های کامپوننت

به طور پیش‌فرض، تمام bindingها در Hilt بدون محدوده هستند. این بدان معناست که هر بار که برنامه شما binding را درخواست می‌کند، Hilt یک نمونه جدید از نوع مورد نیاز ایجاد می‌کند.

در این مثال، هر بار که Hilt AnalyticsAdapter به عنوان یک وابستگی به نوع دیگر یا از طریق تزریق فیلد (مانند ExampleActivity ) ارائه می‌دهد، Hilt یک نمونه جدید از AnalyticsAdapter ارائه می‌دهد.

با این حال، هیلت همچنین اجازه می‌دهد که یک اتصال به یک کامپوننت خاص محدود شود. هیلت فقط یک بار به ازای هر نمونه از کامپوننتی که اتصال به آن محدود شده است، یک اتصال محدود ایجاد می‌کند و همه درخواست‌ها برای آن اتصال، همان نمونه را به اشتراک می‌گذارند.

جدول زیر حاشیه‌نویسی‌های دامنه (scope annotations) را برای هر کامپوننت تولید شده فهرست می‌کند:

کلاس اندروید مولفه تولید شده محدوده
Application SingletonComponent @Singleton
Activity ActivityRetainedComponent @ActivityRetainedScoped
ViewModel ViewModelComponent @ViewModelScoped
Activity ActivityComponent @ActivityScoped
Service ServiceComponent @ServiceScoped

در این مثال، اگر AnalyticsAdapter با استفاده از @ActivityScoped به ActivityComponent محدود کنید، Hilt نمونه‌ی یکسانی از AnalyticsAdapter را در طول حیات activity مربوطه ارائه می‌دهد:

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

فرض کنید AnalyticsService یک وضعیت داخلی دارد که نیاز دارد هر بار از یک نمونه استفاده شود - نه تنها در ExampleActivity ، بلکه در هر کجای برنامه. در این حالت، مناسب است که AnalyticsService به SingletonComponent محدود کنیم. نتیجه این است که هر زمان که کامپوننت نیاز به ارائه نمونه‌ای از AnalyticsService داشته باشد، هر بار نمونه مشابهی را ارائه می‌دهد.

مثال زیر نحوه‌ی تعیین محدوده‌ی یک اتصال به یک کامپوننت در ماژول Hilt را نشان می‌دهد. محدوده‌ی یک اتصال باید با محدوده‌ی کامپوننتی که در آن نصب شده است، مطابقت داشته باشد، بنابراین در این مثال باید AnalyticsService به جای ActivityComponent در SingletonComponent نصب کنید:

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

برای کسب اطلاعات بیشتر در مورد دامنه‌های کامپوننت Hilt، به Scoping در اندروید و Hilt مراجعه کنید.

سلسله مراتب اجزا

نصب یک ماژول در یک کامپوننت، امکان دسترسی به اتصالات آن را به عنوان وابستگی به سایر اتصالات در آن کامپوننت یا در هر کامپوننت فرزند زیر آن در سلسله مراتب کامپوننت فراهم می‌کند.

ActivityComponent زیر شاخه‌ی ActivityRetainedComponent است. ViewModelComponent زیر شاخه‌ی ActivityRetainedComponent است. ActivityRetainedComponent و ServiceComponent زیر شاخه‌ی SingletonComponent هستند.
شکل ۱. سلسله مراتب اجزایی که هیلت تولید می‌کند.

اتصالات پیش‌فرض کامپوننت

هر کامپوننت Hilt با مجموعه‌ای از اتصالات پیش‌فرض ارائه می‌شود که Hilt می‌تواند آن‌ها را به عنوان وابستگی به اتصالات سفارشی شما تزریق کند. توجه داشته باشید که این اتصالات مربوط به نوع فعالیت عمومی هستند و نه هیچ زیرکلاس خاصی. دلیل این امر این است که Hilt از یک تعریف کامپوننت فعالیت واحد برای تزریق همه فعالیت‌ها استفاده می‌کند. هر فعالیت نمونه متفاوتی از این کامپوننت دارد.

کامپوننت اندروید اتصالات پیش‌فرض
SingletonComponent Application
ActivityRetainedComponent Application
ViewModelComponent SavedStateHandle
ActivityComponent Application ، Activity
ServiceComponent Application ، Service

اتصال زمینه برنامه همچنین با استفاده از @ApplicationContext قابل دسترسی است. برای مثال:

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

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

اتصال زمینه فعالیت همچنین با استفاده از @ActivityContext قابل دسترسی است. برای مثال:

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

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

تزریق وابستگی‌ها در کلاس‌هایی که توسط Hilt پشتیبانی نمی‌شوند

در Compose، الگوی استاندارد این است که وابستگی‌ها را با استفاده از تزریق سازنده به @HiltViewModel تزریق کنید و سپس از hiltViewModel() درون composable خود برای دسترسی به ViewModel استفاده کنید. در حالی که Hilt از رایج‌ترین کلاس‌های اندروید پشتیبانی می‌کند، ممکن است همچنان با کلاس‌های پشتیبانی نشده‌ای مواجه شوید که در آن‌ها نیاز به انجام تزریق فیلد داشته باشید.

در این موارد، می‌توانید با استفاده از حاشیه‌نویسی @EntryPoint یک نقطه ورود ایجاد کنید. نقطه ورود مرز بین کدی است که توسط Hilt مدیریت می‌شود و کدی که توسط Hilt مدیریت نمی‌شود. این نقطه‌ای است که کد برای اولین بار وارد نمودار اشیاء تحت مدیریت Hilt می‌شود. نقاط ورود به Hilt اجازه می‌دهند از کدی استفاده کند که Hilt مدیریت نمی‌کند تا وابستگی‌هایی را در نمودار وابستگی ارائه دهد.

برای مثال، Hilt مستقیماً از ارائه‌دهندگان محتوا پشتیبانی نمی‌کند. اگر می‌خواهید یک ارائه‌دهنده محتوا از Hilt برای دریافت برخی وابستگی‌ها استفاده کند، باید رابطی تعریف کنید که برای هر نوع اتصال مورد نظر شما با @EntryPoint حاشیه‌نویسی شده باشد و شامل توصیف‌کننده‌ها باشد. سپس @InstallIn برای مشخص کردن مؤلفه‌ای که نقطه ورود در آن نصب می‌شود، به صورت زیر اضافه کنید:

class ExampleContentProvider : ContentProvider() {

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

  ...
}

برای دسترسی به یک نقطه ورودی، از متد استاتیک مناسب از EntryPointAccessors استفاده کنید. پارامتر باید یا نمونه کامپوننت یا شیء @AndroidEntryPoint باشد که به عنوان نگهدارنده کامپوننت عمل می‌کند. مطمئن شوید که کامپوننتی که به عنوان پارامتر ارسال می‌کنید و متد استاتیک EntryPointAccessors هر دو با کلاس اندروید در حاشیه‌نویسی @InstallIn در رابط @EntryPoint مطابقت دارند:

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

در این مثال، شما باید از ApplicationContext برای بازیابی نقطه ورود استفاده کنید زیرا نقطه ورود در SingletonComponent نصب شده است. اگر متغیری که می‌خواستید بازیابی کنید در ActivityComponent بود، به جای آن از ActivityContext استفاده می‌کردید.

دسته و خنجر

Hilt کتابخانه‌ی پیشنهادی رسمی برای تزریق وابستگی در اندروید است. این کتابخانه روشی استاندارد، خودمحور و کارآمد برای پیاده‌سازی تزریق وابستگی در برنامه‌ی شما ارائه می‌دهد که به‌طور خاص برای معماری‌های Jetpack Compose و single-activity بهینه‌سازی شده است.

اهداف هیلت به شرح زیر است:

  • برای ایجاد مجموعه‌ای استاندارد از کامپوننت‌ها و حوزه‌ها به منظور سهولت در راه‌اندازی، خوانایی و اشتراک‌گذاری کد بین برنامه‌ها.
  • برای ارائه روشی آسان برای تهیه‌ی اتصالات مختلف به انواع مختلف ساخت، مانند آزمایش، اشکال‌زدایی یا انتشار.

از آنجا که سیستم عامل اندروید بسیاری از کلاس‌های چارچوب خود را نمونه‌سازی می‌کند، استفاده از Dagger در یک برنامه اندروید مستلزم نوشتن مقدار قابل توجهی کد تکراری است. Hilt کد تکراری مورد نیاز برای استفاده از Dagger در یک برنامه اندروید را کاهش می‌دهد. Hilt به طور خودکار موارد زیر را تولید و ارائه می‌دهد:

  • کامپوننت‌هایی برای ادغام کلاس‌های فریم‌ورک اندروید با Dagger که در غیر این صورت باید به صورت دستی ایجاد می‌شدند.
  • حاشیه‌نویسی‌های محدوده برای استفاده با کامپوننت‌هایی که Hilt به طور خودکار تولید می‌کند.
  • اتصالات از پیش تعریف شده برای نمایش کلاس‌های اندروید مانند Application یا Activity .
  • توصیف‌کننده‌های از پیش تعریف‌شده برای نمایش @ApplicationContext و @ActivityContext .

کد Dagger و Hilt می‌توانند در یک کدبیس مشترک وجود داشته باشند. با این حال، در بیشتر موارد بهتر است از Hilt برای مدیریت تمام استفاده‌های Dagger در اندروید استفاده کنید. برای مهاجرت پروژه‌ای که از Dagger به Hilt استفاده می‌کند، به راهنمای مهاجرت مراجعه کنید.

منابع اضافی

برای کسب اطلاعات بیشتر در مورد Hilt، به منابع اضافی زیر مراجعه کنید.

نمونه‌ها

وبلاگ‌ها

محتوا را مشاهده می‌کند