این نوشتار مربوط به بخش ششم از کُدلب آموزشی استفاده از Dagger در پروژه اندرویدی به زبان کاتلین هست و میتونید بخش قبلی رو از اینجا بخونید.
بیایید در ادامه جریان Registration رو کامل کنیم، هنوز فرگمنتهای این فیچر از DI دستی استفاده میکنند. دو تا فرگمنت EnterDetailsFragment
و TermsAndConditionsFragment
رو هم مانند اکتیویتیها به متدهای کلاس AppComponent اضافه میکنیم.
فرگمنت EnterDetailsFragment
رو باز کنید تا ببینیم چه فیلدهایی رو میخواهیم به دگر معرفی کنیم؟ دو تا ویومدل داره. از طریق فیلد اینجکشن این دو ویو مدل را به دگر معرفی می کنیم و مودیفایر private را هم حذف می کنیم.
و باید مقدار دهی دستی ویومدل ها را هم از کد حذف کنیم.
حالا وقتشه که از نمونه appComponent که در کلاس اپلیکیشن قراره داره برای Inject فرگمنت ها استفاده کنیم. در فرگمنت متد on Attach را اضافه کنید و کد مربوط به Inject را در این متد بعد از super.onAttach قرار دهید.
در اکتیویتی، درخواست Inject به Dagger در متد on Create و قبل از super نوشته میشود.
در فرگمنت، درخواست Inject به Dagger در متد on Attach و بعد از super نوشته میشود.
فقط ویومدل مربوط به این فرگمنت یعنی RegistrationViewModel
مونده که از قبل به دَگِر معرفی شده.
پس کارمون با فرگمنت EnterDetailsFragment
تمومه! همین کارها رو با فرگمنتTermsAndConditionsFragment
هم انجام میدهیم:
1- فیلدهایی که قراره توسط دگر تامین وابستگی بشوند رو با @Inject انوتیت می کنیم (مثلا registrationViewModel
) و مودیفایر private رو حذف میکنیم.
2. ساخت نمونه از registrationViewModel
رو حذف میکنیم.چون این کار وظیفه Dagger هست.
3. درخواست Inject به دَگِر را در متد onAttach ارسال میکنیم.
پروژه را اجرا کنید.
چه اتفاقی افتاد؟ بعد از ثبت نام برنامه کرش کرد! مشکل اینه که instanceهای متفاوتی از RegistrationViewModel
به RegistrationActivity
و EnterDetailsFragment
و TermsAndConditionsFragment
تزریق شده است. اما این آرمان ما نبود! ما میخواستیم یک instance یکسان از این ویومدل بین اکتیویتی و فرگمنتهاش به اشتراک گذاشته بشه!
چقدر شبیه مشکلی که با UserManager داشتیمه نه؟ پس بیاییم ویومدل رو Singleton کنیم چطوره؟
خب در این لحظه مشکلمون حل میشه اما در آینده مشکلاتی بوجود میاد.
میخواهیم فرگمنتهای مربوط به Registration از ویومدل یکسانی که از اکتیویتی میاد استفاده کنند و همونو reuse کنند اما اگر اکتیویتی تغییر کرد، instance ویومدل هم عوض بشه.
پس باید instance ویومدل به لایف سایکل اکتیویتی scope بشه نه کل برنامه!
میتونیم یک کامپوننت جدید برای Register بسازیم و ویومدل رو به اون scope کنیم. برای اینکار از Dagger subcomponents استفاده میکنیم.
ساب کامپوننت ها کامپوننت هایی هستند که گراف Dagger رو از کامپوننت والد ارث بری می کنند.بنابراین همه ی آبجکتهایی که در کامپوننت والد provide شدند در این ساب کامپوننت ها provide خواهند شد. با این روش آبجکتی که در ساب کامپوننت هست می تونه به آبجکتی که در کامپوننت والد provide شده، وابستگی داشته باشد.
برای ایجاد subComponent مراحل زیر را می رویم:
RegistrationComponent.kt
در پکیج registration بسازیدRegistrationComponent
بسازه، یه متد به AppComponent اضافه میکنیم تا فکتوری، ساب کامپوننت RegistrationComponent
رو برگردونه.?به این فکر کنید اگر اینکارو نمی کردیم چی میشد و راه حل چی بود؟ آیا این روش کد تمیز تری بهمون میده؟
دو تا راه متفاوت برای ارتباط با گراف Dagger وجود داره:
1- متدی داشته باشیم که خروجی اش unit باشه(در جاوا void) و پارامتر ورودی اش کلاسی باشد که میخواهیم فیلد اینجکشن را در آن فعال کنیم. (مثلfun inject(activity: MainActivity)
)
2- متدی داشته باشیم که خروجی اش تایپی باشه که میخواهیم از گراف بدست بیاریم (مثلfun registrationComponent(): RegistrationComponent.Factory
که تایپRegistrationComponent
رو بهمون میده )
RegistrationActivity
بتونه از فکتوری RegistrationComponent
استفاده کنه و ازش instance بسازه. در واقع این متد تایپ RegistrationComponent
رو از گراف در اختیارمون قرار داد.چطور به AppComponent بگیم که RegistrationComponent یکی از subcomponentهای توست و براش کدهای لازم رو تولید کن؟
از طریق DaggerModule!
تو پکیج di یک ماژول به نام AppSubcomponents
میسازیم و با @Module
حاشیه نویسیاش می کنیم. تو همین @Module
در بخش پارامتر subcomponents
نام ساب کامپوننتی که ساختیم یعنی RegistrationComponent
رو اضافه میکنیم.
همچنین اسم این ماژول جدید رو تو لیست ماژولهای AppComponent
اضافه میکنیم.
حالا دیگه AppComponent از ساب کامپوننتاش خبر داره!
همان طور که در پایین سمت چپ گراف می بینید کلاس های ویو (دو فرگمنت و یک اکتیویتی) توسط RegistrationComponent
اینجکت شده اند. از آنجا که RegistrationViewModel
و EnterDetailsViewModel
فقط توسط کلاسهایی که از RegistrationComponent
استفاده میکنند درخواست شدهاند، بخشی از این subcomponent هست بجای AppComponent.
در بخش بعدی کُدلب Scope کردن SubComponent ها را خواهید آموخت.
کُدلَب استفاده از دَگر در برنامه اندرویدی (7-Scoping SubComponent)
کُدلَب استفاده از دَگِر در برنامه اندرویدی (5-استفاده از Scope)
کُدلَب استفاده از دَگر در برنامه اندرویدی (4-تزریق گراف به اکتیوتی)
کُدلَب استفاده از دَگِر در برنامه اندرویدی (3-انوتیشنها)