إدخال المهام التابعة باستخدام Hilt

Hilt هي مكتبة حقن التبعية لنظام Android من شأنها الحد من النص النموذجي. من تنفيذ حقن التبعية اليدوية في مشروعك. تنفيذ التبعية اليدوية حقن الموقع يتطلب منك إنشاء كل فئة وتبعياتها يدويًا، واستخدام الحاويات لإعادة استخدام وإدارة التبعيات.

يوفر Hilt طريقة قياسية لاستخدام DI في تطبيقك من خلال توفير حاويات لكل فئة Android في مشروعك وإدارة مراحل نشاطها تلقائيًا. تم بناء Hilt في أعلى مكتبة DI الشهيرة. يمكنك استخدام Dagger للاستفادة من صحة وقت التجميع وأداء وقت التشغيل وقابلية التوسّع واستوديو Android الدعم التي توفرها أداة Dagger. لمزيد من المعلومات، راجع الاستقلال Dagger.

يشرح هذا الدليل المفاهيم الأساسية لتطبيق Hilt والحاويات التي يتم إنشاؤها. أُنشأها جون هنتر، الذي كان متخصصًا وتشمل أيضًا عرضًا توضيحيًا حول كيفية بدء تشغيل تطبيق حالي لاستخدام Hilt.

إضافة التبعيات

أولاً، أضِف المكوّن الإضافي hilt-android-gradle-plugin إلى جذر مشروعك. ملف build.gradle:

Groovy

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:

Groovy

...
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 في مشروعك، أضِف ما يلي إلى ملف app/build.gradle:

Groovy

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

Kotlin

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

فئة تطبيق Hilt

يجب أن تحتوي جميع التطبيقات التي تستخدم Hilt على Application التي تمت إضافة تعليقات توضيحية إليها @HiltAndroidApp

تؤدي @HiltAndroidApp إلى إنشاء رموز Hilt، بما في ذلك الفئة الأساسية تطبيقك الذي يعمل كحاوية تبعية على مستوى التطبيق.

Kotlin

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

Java

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

يتم ربط المكوِّن الذي تم إنشاؤه بخاصية Hilt بعنصر Application. دورة الحياة ويوفر التبعيات إليها. بالإضافة إلى ذلك، فهو المسؤول الرئيسي من مكونات التطبيق، مما يعني أن المكونات الأخرى يمكنها الوصول إلى والتبعيات التي توفرها.

إدخال الموارد التابعة في صفوف Android

بعد إعداد Hilt في صف Application وعلى مستوى التطبيق مدى التوفّر، يمكن أن يوفر Hilt تبعيات لفئات 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 التي تعتمد عليها. على سبيل المثال، إذا قمت بإضافة تعليق توضيحي فيجب عليك أيضًا إضافة تعليق توضيحي لأي أنشطة تستخدم فيها .

ينشئ تطبيق "@AndroidEntryPoint" مكوّن Hilt فردي لكل نظام Android. الفصل في مشروعك. يمكن أن تتلقى هذه المكونات تبعيات من الفئات الرئيسية المعنية كما هو موضح في المكوّن التسلسل الهرمي:

للحصول على عناصر الاعتمادية من مكوِّن، استخدِم التعليق التوضيحي @Inject لتنفيذ إدخال الحقل:

Kotlin

@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() {

  @Inject lateinit var analytics: AnalyticsAdapter
  ...
}

Java

@AndroidEntryPoint
public class ExampleActivity extends AppCompatActivity {

  @Inject
  AnalyticsAdapter analytics;
  ...
}

يمكن أن تشتمل الفئات التي يتم حقنها عن طريق Hilt على فئات أساسية أخرى تستخدم الحقن أيضًا. ولا تحتاج هذه الصفوف إلى التعليق التوضيحي @AndroidEntryPoint إذا كانت تجريدي.

لمعرفة المزيد من المعلومات حول دورة الحياة التي يتم فيها إدخال فئة Android، راجع أعمار المكوّنات.

تعريف عمليات ربط Hilt

ولإجراء حقن الحقل، يحتاج Hilt إلى معرفة طريقة توفير مثيلات والتبعيات الضرورية من المكون المقابل. يحتوي الربط على المعلومات اللازمة لتوفير مثيلات من نوع ما كتبعية.

إحدى الطرق لتقديم معلومات ملزمة إلى Hilt هي إدخال الدالة الإنشائية. استخدام التعليق التوضيحي @Inject على الدالة الإنشائية لفئة معيّنة لإعلام هيلت بكيفية اذكر أمثلة من تلك الفئة:

Kotlin

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

Java

public class AnalyticsAdapter {

  private final AnalyticsService service;

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

معاملات الدالة الإنشائية التي تم التعليق عليها لفئة ما هي تبعيات لتلك الفئة. في المثال، تتضمّن AnalyticsAdapter السمة AnalyticsService كسمة والتبعية. ومن ثمّ، يتعين على Hilt أيضًا معرفة كيفية تقديم مثيلات AnalyticsService

وحدات الجناح

أحيانًا لا يمكن إدخال دالة إنشائية. يمكن أن يحدث هذا لعدة الأسباب. على سبيل المثال، لا يمكنك إدخال دالة إنشائية لواجهة. يمكنك أيضًا لا يمكن لأداة الإنشاء إدخال نوع لا تملكه، مثل فئة من ومكتبة خارجية. في هذه الحالات، يمكنك تزويد Hilt بمعلومات ملزمة. باستخدام وحدات النتائج

وحدة Hilt هي فئة تمت إضافة تعليقات توضيحية إليها باستخدام @Module. مثل Dagger واحدة، فإنها تُعلم Hilt كيفية توفير مثيلات من أنواع معيّنة. وعلى عكس وحدات Dagger، يجب إضافة تعليقات توضيحية إلى وحدات Hilt باستخدام @InstallIn لإعلام Hilt بنظام Android. الفئة التي سيتم استخدام أو تثبيت كل وحدة فيها.

تكون التبعيات التي تقدّمها في وحدات Hilt متاحة في جميع المهام التي تم إنشاؤها. المرتبطة بفئة Android حيث يتم تثبيت وحدة Hilt

إدخال حالات الواجهة باستخدام @Binds

يمكنك الاطّلاع على المثال AnalyticsService. إذا كانت AnalyticsService واجهة، فلن يمكنك تضمين الدالة الإنشائية. بدلاً من ذلك، عليك تزويد Hilt بالربط عن طريق إنشاء دالة مجردة مع تعليقات توضيحية باستخدام @Binds داخلها وحدة Hilt

يحدّد التعليق التوضيحي @Binds أنّ Hilt يحدد طريقة التنفيذ التي يجب استخدامها عندما يكون هناك حاجة إلى ذلك. تقدم مثيلاً للواجهة.

توفّر الدالة التي تحتوي على تعليقات توضيحية المعلومات التالية لجهة Hilt:

  • تخبر الدالة return type 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. يعني هذا التعليق التوضيحي أن جميع تتوفر الموارد التابعة في AnalyticsModule في جميع أنشطة التطبيق.

إدخال مثيلات باستخدام @Provides

لا تكون الواجهات هي الحالة الوحيدة التي لا يمكنك فيها إدخال نوع من الدالة الإنشائية. ومن غير الممكن أيضًا إدخال الدالة الإنشائية إذا لم تكن تملك الفئة لأنها من مكتبة خارجية (فصول مثل المراجعة النهائية، OkHttpClient، أو قواعد بيانات الغرف)، أو إذا كان يجب سيتم إنشاؤها باستخدام المنشئ التصميم.

بالنظر إلى المثال السابق. إذا لم تكن تملك AnalyticsService بشكل مباشر يمكنك إخبار Hilt بكيفية تقديم مثيلات من هذا النوع عن طريق إنشاء داخل وحدة Hilt وإضافة تعليقات توضيحية إلى هذه الدالة باستخدام @Provides.

توفّر الدالة المُشار إليها المعلومات التالية إلى Hilt:

  • تخبر الدالة return type Hilt بنوع الدالة الذي توفره المثيلات منه.
  • تخبر معاملات الدالة Hilt بتبعيات النوع المقابل.
  • يخبر نص الدالة 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 مع أداة الاعتراض بالنسبة والخدمات الأخرى، فقد تحتاج إلى اعتراض المكالمات بطريقة مختلفة. في ذلك، عليك إخبار Hilt بكيفية تقديم عمليتَي تنفيذ مختلفتَين 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 مع @Provides. كلتا الطريقتين لهما نفس نوع الإرجاع، لكن المؤهلات تصنفهما على أنهما الأربطة المختلفة:

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

كأفضل ممارسة، إذا أضفت مؤهِّل إلى نوع ما، فستضيف مؤهِّلات إلى جميع الطرق الممكنة لتوفير تلك التبعية. ترك القاعدة أو الشائع التنفيذ بدون مؤهِّل يكون عرضة للخطأ وقد يؤدي إلى Hilt لإدخال تبعية خاطئة.

المؤهلات المحددة مسبقًا في 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 المكونات التالية:

مكوّن 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 كاعتمادية، من خلال نوع آخر أو من خلال حقن الحقل (كما في ExampleActivity)، يوفر Hilt مثيل جديد لـ AnalyticsAdapter.

ومع ذلك، تسمح 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

في المثال، إذا طبّقت النطاق 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.

التدرّج الهرمي للمكوّنات

يسمح تثبيت وحدة في مكوَّن بالوصول إلى روابطها كوحدة تبعية الأربط الأخرى في هذا المكون أو في أي مكون فرعي أدناه في التسلسل الهرمي للمكونات:

يتضمن ViewWithFragmentComponent ضمن FragmentComponent. مكوِّن التجزئة
    وViewComponent ضمن النشاط. عنصر النشاط ضمن
    ActivityRetainedComponent. يعد ViewModelComponent ضمن
    ActivityRetainedComponent. مكوِّن ActivityRetainedمكوِّن وخدمته
    ضمن IndividualtonComponent.
الشكل 1. التسلسل الهرمي للمكونات التي 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. مثلاً:

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

إدخال تبعيات في فئات لا يدعمها Hilt

تأتي Hilt متوافقة مع فئات Android الأكثر شيوعًا. ومع ذلك، قد بحاجة إلى إجراء حقن الحقل في فئات لا يدعمها Hilt.

وفي هذه الحالات، يمكنك إنشاء نقطة دخول باستخدام @EntryPoint. التعليق التوضيحي. نقطة الدخول هي الحد الفاصل بين الرمز الذي يديره Hilt والرموز غير البرمجية غير ذلك. إنها النقطة التي يتم فيها إدخال الرمز لأول مرة في الرسم البياني الأخرى التي يديرها Hilt. تسمح نقاط الإدخال للدالة Hilt باستخدام الرمز الذي ينشئه Hilt عدم القدرة على تقديم التبعيات داخل الرسم البياني للتبعية.

على سبيل المثال، لا تتوافق 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 تتطابق كلتاهما مع فئة 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 وخنجر

تم بناء Hilt أعلى أداة Dagger. وهي مكتبة حقن التبعية، مما يوفر طريقة معيارية لدمج Dagger في تطبيق Android.

في ما يتعلق بأداة Dagger، تتمثل أهداف Hilt في ما يلي:

  • لتبسيط البنية الأساسية المتعلقة بأداة Dagger في تطبيقات Android.
  • لإنشاء مجموعة قياسية من المكونات والنطاقات لتسهيل الإعداد، وسهولة القراءة، ومشاركة الرموز بين التطبيقات
  • لتوفير طريقة سهلة لتوفير روابط مختلفة لأنواع مختلفة من التصميمات، مثل الاختبار أو تصحيح الأخطاء أو الإصدار.

لأنّ نظام التشغيل Android ينشئ مثيلاً للعديد من إطار العمل الخاص به فإن استخدام Dagger في أحد تطبيقات Android يتطلب كتابة مجموعة كبيرة مقدار النص النموذجي. يقلل Hilt من رمز النص النموذجي المضمّن في باستخدام Dagger في أحد تطبيقات Android. تقوم Hilt تلقائيًا بإنشاء ما يلي:

  • مكونات دمج فئات أطر عمل Android مع Dagger التي سيحتاج إلى إنشائها يدويًا بخلاف ذلك.
  • تعليقات توضيحية للنطاق لاستخدامها مع المكوّنات التي ينشئها Hilt تلقائيًا.
  • عمليات الربط المحدَّدة مسبقًا لتمثيل فئات Android، مثل Application أو Activity
  • المؤهلات المحدّدة مسبقًا لتمثيل @ApplicationContext @ActivityContext

يمكن أن يتواجد رمزا Dagger وHlt في نفس قاعدة الرموز. ومع ذلك، في معظم الحالات هو أفضل استخدام Hilt لإدارة كل استخدامك لأداة Dagger على Android. لنقل البيانات يستخدم Dagger إلى Hilt، راجع قسم نقل البيانات ودليل نقل البيانات تطبيق Dagger على Hilt درس تطبيقي حول الترميز.

مصادر إضافية

لمعرفة المزيد من المعلومات عن Hilt، يمكنك الاطّلاع على المراجع الإضافية التالية.

نماذج

الدروس التطبيقية حول الترميز

المدوّنات