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

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

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

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

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

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

شیار

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 خود اضافه کنید:

شیار

...
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 از ویژگی های جاوا 8 استفاده می کند. برای فعال کردن جاوا 8 در پروژه خود، موارد زیر را به فایل app/build.gradle اضافه کنید:

شیار

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 استفاده می‌کنند باید دارای یک کلاس Application باشند که با @HiltAndroidApp حاشیه‌نویسی شده است.

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

کاتلین

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

جاوا

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

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

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

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

کاتلین

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

جاوا

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

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

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

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

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

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

کاتلین

@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() {

  @Inject lateinit var analytics: AnalyticsAdapter
  ...
}

جاوا

@AndroidEntryPoint
public class ExampleActivity extends AppCompatActivity {

  @Inject
  AnalyticsAdapter analytics;
  ...
}

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

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

اتصالات هیلت را تعریف کنید

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

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

کاتلین

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 ، به Hilt اطلاع می دهد که چگونه نمونه هایی از انواع خاص را ارائه دهد. برخلاف ماژول‌های Dagger، باید ماژول‌های Hilt را با @InstallIn حاشیه‌نویسی کنید تا به Hilt بگویید هر ماژول در کدام کلاس Android استفاده یا نصب می‌شود.

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

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

مثال AnalyticsService را در نظر بگیرید. اگر AnalyticsService یک رابط است، نمی توانید آن را تزریق کنید. در عوض، با ایجاد یک تابع انتزاعی مشروح شده با @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
}

جاوا

public interface AnalyticsService {
  void analyticsMethods();
}

// Constructor-injected, because Hilt needs to know how to
// provide instances of AnalyticsServiceImpl, too.
public class AnalyticsServiceImpl implements AnalyticsService {
  ...
  @Inject
  AnalyticsServiceImpl(...) {
    ...
  }
}

@Module
@InstallIn(ActivityComponent.class)
public abstract class AnalyticsModule {

  @Binds
  public abstract AnalyticsService bindAnalyticsService(
    AnalyticsServiceImpl analyticsServiceImpl
  );
}

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

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

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

مثال قبلی را در نظر بگیرید. اگر مستقیماً مالک کلاس AnalyticsService نیستید، می‌توانید به Hilt بگویید که چگونه نمونه‌هایی از این نوع را با ایجاد یک تابع در ماژول 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)
  }
}

جاوا

@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 استفاده می‌کنید، تعریف کنید:

کاتلین

@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 باید بداند که چگونه یک نمونه از نوع مطابق با هر واجد شرایط ارائه دهد. در این مورد، می توانید از یک ماژول 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()
  }
}

جاوا

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

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

کاتلین

// 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 برخی از واجد شرایط از پیش تعریف شده را ارائه می دهد. برای مثال، از آنجایی که ممکن است به کلاس Context از برنامه یا اکتیویتی نیاز داشته باشید، Hilt واجد شرایط @ApplicationContext و @ActivityContext را ارائه می دهد.

فرض کنید کلاس AnalyticsAdapter از مثال به زمینه فعالیت نیاز دارد. کد زیر نحوه ارائه زمینه فعالیت به AnalyticsAdapter را نشان می دهد:

کاتلین

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 که می‌توانید در آن تزریق فیلد انجام دهید، یک مؤلفه Hilt مرتبط وجود دارد که می‌توانید در حاشیه‌نویسی @InstallIn به آن مراجعه کنید. هر جزء Hilt وظیفه تزریق اتصالات خود را به کلاس Android مربوطه دارد.

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

Hilt اجزای زیر را ارائه می دهد:

جزء هیلت انژکتور برای
SingletonComponent Application
ActivityRetainedComponent N/A
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 به عنوان وابستگی به نوع دیگری یا از طریق تزریق فیلد (مانند ExampleActivity ) ارائه می‌کند، Hilt نمونه جدیدی از AnalyticsAdapter ارائه می‌کند.

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

جدول زیر حاشیه نویسی محدوده برای هر جزء تولید شده را فهرست می کند:

کلاس اندروید جزء تولید شده دامنه
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 را در طول عمر فعالیت مربوطه ارائه می‌کند:

کاتلین

@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 را محدود کنید. محدوده یک binding باید با محدوده مؤلفه ای که در آن نصب شده است مطابقت داشته باشد، بنابراین در این مثال باید 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)
  }
}

جاوا

// 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، به Scoping در Android و Hilt مراجعه کنید.

سلسله مراتب مؤلفه ها

نصب یک ماژول در یک کامپوننت به پیوندهای آن اجازه می دهد تا به عنوان وابستگی به سایر اتصالات در آن مؤلفه یا در هر مؤلفه فرزند زیر آن در سلسله مراتب مؤلفه دسترسی داشته باشید:

ViewWithFragmentComponent در قسمت FragmentComponent قرار دارد. قطعه قطعه     و ViewComponent تحت ActivityComponent قرار دارند. ActivityComponent در زیر است     ActivityRetainedComponent. ViewModelComponent در زیر است     ActivityRetainedComponent. ActivityRetainedComponent و ServiceComponent     تحت SingletonComponent هستند.
شکل 1. سلسله مراتب اجزایی که هیلت تولید می کند.

اتصالات پیش فرض مؤلفه

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

کامپوننت اندروید صحافی های پیش فرض
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 در دسترس است. به عنوان مثال:

کاتلین

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 در دسترس است. به عنوان مثال:

کاتلین

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 از رایج ترین کلاس های اندروید پشتیبانی می کند. با این حال، ممکن است لازم باشد در کلاس هایی که Hilt پشتیبانی نمی کند، تزریق فیلد انجام دهید.

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

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

کاتلین

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 هر دو با کلاس Android در حاشیه نویسی @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()
    ...
  }
}

جاوا

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 ساخته شده است، که یک راه استاندارد برای گنجاندن Dagger در یک برنامه اندروید ارائه می دهد.

با توجه به داگر، اهداف هیلت به شرح زیر است:

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

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

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

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

منابع اضافی

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

نمونه ها

Codelabs

وبلاگ ها