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

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

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

يشرح هذا الدليل المفاهيم الأساسية لتطبيق 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

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

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

للحصول على عناصر الاعتمادية من مكوِّن، استخدِم التعليق التوضيحي @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 كيفية توفير نُسخ من التبعيات الضرورية من المكوّن المقابل. يحتوي الربط على المعلومات اللازمة لتوفير مثيلات من نوع ما كتبعية.

من الطرق التي تتيح تقديم معلومات الربط إلى 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.

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

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

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

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

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 يمكنك فيها إدخال الحقل، هناك مكوِّن 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 طوال مدة النشاط المقابل:

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 يجب أن يتطابق نطاق الربط مع نطاق المكوّن الذي تم تثبيته فيه، لذا في هذا المثال، يجب تثبيت AnalyticsService في SingletonComponent بدلاً من ActivityComponent:

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. يقع ActivityComponent ضمن
    ActivityRetainedComponent. ViewModelComponent ضمن
    ActivityRetainedComponent يقع كلّ من ActivityRetainedComponent وServiceComponent
    ضمن SingletonComponent.
الشكل 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. مثلاً:

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 للحصول على بعض التبعيات، عليك تحديد واجهة مُشارَك فيها تعليقًا توضيحيًا باستخدام @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 تتطابق كلتاهما مع فئة Android في التعليق التوضيحي @InstallIn على واجهة "@EntryPoint":

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.

أداة 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 وHilt قاعدة الرموز البرمجية نفسها. ومع ذلك، في معظم الحالات هو أفضل استخدام Hilt لإدارة كل استخدامك لأداة Dagger على Android. لنقل مشروع يستخدم Dagger إلى Hilt، اطّلِع على دليل نقل البيانات ونقل بيانات تطبيقك الذي يستخدم Dagger إلى Hilt في codelab.

مصادر إضافية

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

نماذج

تعرَّف على كيفية تنفيذ عمليات الضبط المُدارة التي يمكن أن تغيّرها تطبيقات أخرى على الجهاز نفسه.

توفِّر ميزات المؤسسة من Android للمؤسسات بيئة آمنة ومرنة نظام Android للجوّال الأساسي الموحد — الذي يجمع بين الأجهزة والتطبيقات والإدارة. تطبيقات Android متوافقة مع ميزات المؤسسة من Android تلقائيًا. ومع ذلك، هناك ميزات إضافية يمكنك استخدامها لإنشاء

تعرَّف على كيفية التأكُّد من عمل تطبيقاتك بسلاسة في بيئة الشركة من خلال اتّباع بعض أفضل الممارسات.

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

المدوّنات