Hilt هي مكتبة حقن التبعية لنظام Android تقلِّل من النصوص النموذجية لتنفيذ إدخال التبعية يدويًا في مشروعك. يتطلّب إجراء حقن تبعية يدوية إنشاء كل فئة وتبعياتها يدويًا، واستخدام الحاويات لإعادة استخدام تبعيات وإدارتها.
توفّر Hilt طريقة قياسية لاستخدام "التبعية التعريفية" في تطبيقك من خلال توفير حاويات لكل فئة Android في مشروعك وإدارة دورات حياتها تلقائيًا. يستند Hilt إلى مكتبة DI الشهيرة Dagger للاستفادة من صحة وقت التجميع وأداء وقت التشغيل وقابلية التوسع والتوافق مع "استوديو Android" الذي يوفّره تطبيق 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 في codelab.
مصادر إضافية
لمزيد من المعلومات عن Hilt، اطّلِع على المراجع الإضافية التالية.
نماذج
الدروس التطبيقية حول الترميز
المدوّنات
- حقن التبعيات على Android باستخدام Hilt
- تحديد النطاق في Android و Hilt
- إضافة مكوّنات إلى التسلسل الهرمي لـ Hilt
- نقل بيانات تطبيق Google I/O إلى IDE Hilt