Hilt هي مكتبة لنظام Android تعمل على حقن التبعيات، ما يقلل من تكرار الخطوات المتكررة عند إجراء عملية حقن التبعيات يدويًا في مشروعك. يتطلّب إجراء حقن تبعية يدوية إنشاء كل فئة وتبعياتها يدويًا، واستخدام الحاويات لإعادة استخدام تبعيات وإدارتها.
توفّر Hilt طريقة قياسية لاستخدام "التبعية التعريفية" في تطبيقك من خلال توفير حاويات لكل فئة Android في مشروعك وإدارة دورات حياتها تلقائيًا. تم إنشاء Hilt استنادًا إلى مكتبة DI الرائجة Dagger للاستفادة من الدقة في وقت الترجمة وأداء وقت التشغيل وقابلية التوسّع ودعم Android Studio الذي تقدّمه Dagger. لمزيد من المعلومات، يُرجى الاطّلاع على مقبض السيف والخنجر.
يوضّح هذا الدليل المفاهيم الأساسية لواجهة برمجة التطبيقات Hilt والحاويات التي يتم إنشاؤها باستخدامها. ويتضمن أيضًا عرضًا توضيحيًا لكيفية بدء تشغيل تطبيق حالي لاستخدام Hilt.
إضافة التبعيات
أولاً، أضِف المكوّن الإضافي hilt-android-gradle-plugin
إلى ملف ملف build.gradle
الجذر لمشروعك:
رائع
plugins { ... id 'com.google.dagger.hilt.android' version '2.51.1' apply false }
Kotlin
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 }
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-android-compiler:2.51.1") } // Allow references to generated code kapt { correctErrorTypes = true }
تستخدِم Hilt ميزات Java 8. لتفعيل Java 8 في
مشروعك، أضِف ما يلي إلى ملف app/build.gradle
:
رائع
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 هي حقن مُنشئ العنصر. استخدِم annotation @Inject
على الدالة الإنشائية لفئة معيّنة لإعلام Hilt بكيفية
توفير نُسخ من تلك الفئة:
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 بمعلومات الربط باستخدام وحدات Hilt.
وحدة Hilt هي فئة تمّت إضافة تعليقات توضيحية إليها باستخدام @Module
. مثل وحدة
Dagger، يُعلم Hilt كيفية توفير نُسخ من أنواع معيّنة. على عكس وحدات Dagger،
يجب إضافة تعليقات توضيحية إلى وحدات Hilt باستخدام @InstallIn
لإعلام Hilt بفئة Android
التي سيتم استخدام كل وحدة فيها أو تثبيتها فيها.
تتوفّر التبعيات التي تقدّمها في وحدات Hilt في جميع المكونات المُنشأة والمرتبطة بفئة Android التي تُثبِّت فيها ملف Hilt.
إدراج نُسخ من الواجهات باستخدام @Binds
راجِع المثال AnalyticsService
. إذا كانت AnalyticsService
واجهة،
لا يمكنك حقنها باستخدام طريقة وضع التصميم. بدلاً من ذلك، يمكنك تزويد Hilt بمعلومات الربط
من خلال إنشاء دالة مجردة مع تعليق توضيحي @Binds
داخل ملف
وحدة Hilt.
يُعلم التعليق التوضيحي @Binds
حزمة Hilt بكيفية التنفيذ التي يجب استخدامها عندما تحتاج إلى
توفير مثيل لواجهة.
تقدّم الدالة المُشارَك إليها المعلومات التالية إلى Hilt:
- يُخبر نوع ناتج الدالة حزمة 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
لا تقتصر الحالات التي لا يمكنك فيها حقن نوع باستخدام أسلوب الإنشاء على الواجهات.
لا يمكن أيضًا حقن عنصر الإنشاء إذا لم تكن تملك الفئة لأنّه
يأتي من مكتبة خارجية (مثل فئات
Retrofit أو
OkHttpClient
أو
قواعد بيانات Room)، أو إذا كان يجب
إنشاء النماذج باستخدام نمط
المنشئ.
راجِع المثال السابق. إذا لم تكن تملك فئة AnalyticsService
بشكل مباشر، يمكنك إخبار Hilt بطريقة توفير نُسخ من هذا النوع من خلال إنشاء دالة
داخل وحدة Hilt وإضافة تعليق توضيحي لهذه الدالة باستخدام @Provides
.
توفّر الدالة المُشارَك عليها تعليقات توضيحية المعلومات التالية إلى Hilt:
- يُخبر نوع عرض الدالة أداة 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 كيفية تقديم مثيل من النوع الذي يتوافق
مع كلّ مؤهّل. في هذه الحالة، يمكنك استخدام وحدة 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 أيضًا بتحديد نطاق الربط لمكوّن معيّن. لا تنشئ 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.
التدرّج الهرمي للمكوّنات
يتيح تثبيت وحدة في مكوّن الوصول إلى عمليات الربط الخاصة بها كأحد المتطلّبات لعمليات الربط الأخرى في ذلك المكوّن أو في أي مكوّن ثانوي تحته في التسلسل الهرمي للمكوّنات:
عمليات الربط التلقائية للمكوّنات
يتضمّن كل مكوّن من مكونات 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 للحصول على بعض التبعيات، عليك تحديد واجهة
مُشارَك فيها تعليقًا توضيحيًا باستخدام @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
static
تطابقان مع فئة 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 استنادًا إلى مكتبة 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 في ورشة التعلم.
مصادر إضافية
لمزيد من المعلومات عن Hilt، اطّلِع على المراجع الإضافية التالية.
نماذج
الدروس التطبيقية حول الترميز
المدوّنات
- حقن التبعيات على Android باستخدام Hilt
- تحديد النطاق في Android و Hilt
- إضافة مكوّنات إلى التسلسل الهرمي لـ Hilt
- نقل بيانات تطبيق Google I/O إلى IDE Hilt