فرشته ناجی
فرشته ناجی
خواندن ۴ دقیقه·۳ سال پیش

کُدلَب استفاده از دَگر در برنامه اندرویدی (6-SubComponent)

این نوشتار مربوط به بخش ششم از کُدلب آموزشی استفاده از Dagger در پروژه اندرویدی به زبان کاتلین هست و می‌تونید بخش قبلی رو از اینجا بخونید.

جریان Registration

بیایید در ادامه جریان Registration رو کامل کنیم، هنوز فرگمنت‌های این فیچر از DI دستی استفاده می‌کنند. دو تا فرگمنت EnterDetailsFragmentو TermsAndConditionsFragmentرو هم مانند اکتیویتی‌ها به متدهای کلاس AppComponent اضافه می‌کنیم.

AppComponent.kt
AppComponent.kt

فرگمنت EnterDetailsFragmentرو باز کنید تا ببینیم چه فیلدهایی رو می‌خواهیم به دگر معرفی کنیم؟ دو تا ویومدل داره. از طریق فیلد اینجکشن این دو ویو مدل را به دگر معرفی می کنیم و مودیفایر private را هم حذف می کنیم.

EnterDetailsFragment.kt
EnterDetailsFragment.kt


و باید مقدار دهی دستی ویومدل ها را هم از کد حذف کنیم.

EnterDetailsFragment.kt
EnterDetailsFragment.kt


حالا وقتشه که از نمونه appComponent که در کلاس اپلیکیشن قراره داره برای Inject فرگمنت ها استفاده کنیم. در فرگمنت متد on Attach را اضافه کنید و کد مربوط به Inject را در این متد بعد از super.onAttach قرار دهید.

EnterDetailsFragment.kt
EnterDetailsFragment.kt

عادت خوب کدنویسی

در اکتیویتی، درخواست Inject به Dagger در متد on Create و قبل از super نوشته می‌شود.

در فرگمنت، درخواست Inject به Dagger در متد on Attach و بعد از super نوشته می‌شود.


فقط ویومدل مربوط به این فرگمنت یعنی RegistrationViewModelمونده که از قبل به دَگِر معرفی شده.

RegistrationViewModel
RegistrationViewModel

پس کارمون با فرگمنت EnterDetailsFragmentتمومه! همین کارها رو با فرگمنتTermsAndConditionsFragment هم انجام می‌دهیم:

1- فیلدهایی که قراره توسط دگر تامین وابستگی بشوند رو با @Inject انوتیت می کنیم (مثلا registrationViewModel) و مودیفایر private رو حذف می‌کنیم.
2. ساخت نمونه از registrationViewModelرو حذف می‌کنیم.چون این کار وظیفه Dagger هست.

3. درخواست Inject به دَگِر را در متد onAttach ارسال می‌کنیم.

TermsAndConditionsFragment.kt
TermsAndConditionsFragment.kt

پروژه را اجرا کنید.

چه اتفاقی افتاد؟ بعد از ثبت نام برنامه کرش کرد! مشکل اینه که instanceهای متفاوتی از RegistrationViewModelبه RegistrationActivityو EnterDetailsFragmentو TermsAndConditionsFragmentتزریق شده است. اما این آرمان ما نبود! ما می‌خواستیم یک instance یکسان از این ویومدل بین اکتیویتی و فرگمنت‌هاش به اشتراک گذاشته بشه!

چقدر شبیه مشکلی که با UserManager داشتیمه نه؟ پس بیاییم ویومدل رو Singleton کنیم چطوره؟

خب در این لحظه مشکلمون حل میشه اما در آینده مشکلاتی بوجود میاد.

  • ما نمی خواهیم که instance ویومدل تا وقتی برنامه در حال اجراست در حافظه بمونه حتی وقتی روند ثبت نام یک یوزر به پایان رسید و دیگه ویو مدل رو لازم نداریم!
  • برای هر جریان ثبت نام یک instance متفاوت از ویومدل میخوایم. اگر کاربر ثبت نام و بعد لغو ثبت نام کنه نمی خوایم اطلاعات ثبت نام قبلی در ثبت نام جدید در دسترس باشه.

پس چی میخوایم؟

میخواهیم فرگمنت‌های مربوط به Registration از ویومدل یکسانی که از اکتیویتی میاد استفاده کنند و همونو reuse کنند اما اگر اکتیویتی تغییر کرد، instance ویومدل هم عوض بشه.

پس باید instance ویومدل به لایف سایکل اکتیویتی scope بشه نه کل برنامه!

می‌تونیم یک کامپوننت جدید برای Register بسازیم و ویومدل رو به اون scope کنیم. برای اینکار از Dagger subcomponents استفاده می‌کنیم.



معرفی Dagger subcomponents

ساب کامپوننت ها کامپوننت هایی هستند که گراف Dagger رو از کامپوننت والد ارث بری می کنند.بنابراین همه ی آبجکت‌هایی که در کامپوننت والد provide شدند در این ساب کامپوننت ها provide خواهند شد. با این روش آبجکتی که در ساب کامپوننت هست می تونه به آبجکتی که در کامپوننت والد provide شده، وابستگی داشته باشد.

برای ایجاد subComponent مراحل زیر را می رویم:

  • یک فایل جدید به نام RegistrationComponent.ktدر پکیج registration بسازید
  • یک اینترفیس به نام RegistrationComponent در آن ایجاد و با @Subcomponent حاشیه نویسی‌اش می‌کنیم.
registration/RegistrationComponent.kt
registration/RegistrationComponent.kt


  • همه مواردی که به Registration ربط داره از AppComponent به این subComponent منتقل می‌کنیم.
  • یک اینترفیس فکتوری در این subComponent بسازید تا بتوانیم از آن instance بسازیم.
RegistrationComponent.kt
RegistrationComponent.kt


  • بجای آنکه RegistrationActivity یک instance از RegistrationComponentبسازه، یه متد به AppComponent اضافه می‌کنیم تا فکتوری، ساب کامپوننت RegistrationComponentرو برگردونه.
AppComponent.kt
AppComponent.kt


?به این فکر کنید اگر اینکارو نمی کردیم چی می‌شد و راه حل چی بود؟ آیا این روش کد تمیز تری بهمون میده؟


یادآوری

دو تا راه متفاوت برای ارتباط با گراف 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رو اضافه میکنیم.

AppSubcomponents.kt
AppSubcomponents.kt


همچنین اسم این ماژول جدید رو تو لیست ماژول‌های AppComponentاضافه می‌کنیم.

AppComponent.kt
AppComponent.kt

حالا دیگه AppComponent از ساب کامپوننت‌اش خبر داره!


تصویر گراف برنامه تا این لحظه

همان طور که در پایین سمت چپ گراف می بینید کلاس های ویو (دو فرگمنت و یک اکتیویتی) توسط RegistrationComponentاینجکت شده اند. از آنجا که RegistrationViewModelو EnterDetailsViewModelفقط توسط کلاس‌هایی که از RegistrationComponentاستفاده می‌کنند درخواست شده‌اند، بخشی از این subcomponent هست بجای AppComponent.

در بخش بعدی کُدلب Scope کردن SubComponent ها را خواهید آموخت.


بعدی

کُدلَب استفاده از دَگر در برنامه اندرویدی (7-Scoping SubComponent)

قبلی

کُدلَب استفاده از دَگِر در برنامه اندرویدی (5-استفاده از Scope)

کُدلَب استفاده از دَگر در برنامه اندرویدی (4-تزریق گراف به اکتیوتی)

کُدلَب استفاده از دَگِر در برنامه اندرویدی (3-انوتیشن‌ها)

کُدلَب استفاده از دَگِر در برنامه اندرویدی (2-شروع)

کُدلَب استفاده از دَگِر در برنامه اندرویدی(1-معرفی)

تزریق وابستگیdidependency injectionkotlinکاتلین
برنامه نویس اندروید @NeshanMap
شاید از این پست‌ها خوشتان بیاید