Dagger 2 در اندروید (نصیب اولیه) – راهنمای توسعه یافته
Dagger 2 در اندروید (نصیب اولیه) – راهنمای توسعه یافته
Dagger یک زمینه متناقض در جامعه اندروید محسوب میشود. دعواهای و پیکارهای بیشماری پیرامون آن صورت گرفته میباشد و اکثری از اشخاص بارها نظرخود را در باب آن تغییر تحول دادهاند. اکثر وقت ها نرم افزارنویسها سوابقای از پیشرفت دهندگی دارا هستند که در آن تزریق تعلق کاری سهل وآسان به حساب میآید و از این رو تایید ابهام Dagger به فرصت بیشتری نیاز دارااست که در اکثر زمان ها موردها بسیار بیشتر از مقدار گزینه انتظار میباشد.
امروزه ما در کاتلین با جایگزینهای جذابی مانند Koin یا این که Kodein مواجه هستیم و برخی اشخاص دراین مسیر تکان مینمایند. با این حالا شاید اطلاق کلمه جایگزین برای این مفاد صحیح نباشد، چون آن ها بیشتر خدمت یاب (service locator) میباشند تا یک تزریق کننده طراحی اپلیکیشن در مشهد حقیقی وواقعی تعلق.
البته در غایت می توانیم توافق کنیم که با وجود کلیه علاقه و تنفری که در زمینهی Dagger وجود داراست، Dagger یک کتابخانه کارکشته و طریق سفارش گردیده قانونی برای تزریق تعلق در نرم افزارهای اندروید میباشد.
با در حیث اعلام کردن حقیقت فوق متوجه میشویم که طرزهای بسیار مختلفی چهت نیل به هدف ها شبیه از روش Dagger وجود دارا هستند که بعضا از آنها بسیار غامض محسوب می شوند. ما درین نوشته به رسیدگی رویکردهای متفاوت پرداخته و طرز مطلوب را به شما توضیح می دهیم.
یک سری پیشنهاد کلی
در زمینهی همگی کلاسهایی که مینویسید از «تزریق ساختار» (Construction Injection) استعمال فرمائید.
به مکان کامپوننتهای فرعی، حوزه تعریف و تمجید (Scope) را با به کارگیری از ViewModel در اختیار گرفتن فرمائید.
وجود dagger-android را فراموش نمائید.
دیباچه
دراین نوشتهی علمی فرض می کنیم که شما پیش از اینً تجربیاتی با Dagger داشتهاید. در شرایطیکه اینگونه وجود ندارد، سفارش می کنیم پیش از بازرسی ادامه این نوشتهی علمی به بعضا راهنماهای جانور در این باره مراجعه نمایید. همینطور تمامی مواقعی که دراین نوشته مطرح میشوند در یک نرم افزار معمولی دراین نشانی (+) پیادهسازی گردیدهاند که سفارش میکنیم آن را نیز پژوهش نمایید. سعی گردیده این نرم افزار تا حد قابلیت خرد باشد تا فقطً روی سوژه Dagger تمرکز کنیم.
تزریق ساختار
یکی مواقعی که در Dagger به طور کاملً نادیده گرفته گردیده، گفت و گو «تزریق ساختار» (Construction Injection) میباشد. گه گاه ما چنان به استعمال از ماژولها عادت میکنیم که فراموش می کنیم مورد اجتناب بی نقص از تایپ کردن «متدهای خالق» (Constructor) نیز وجود داراست. به حیث میرسد این دقیقاً مزیت کلیدی Dagger نسبت به Koin و Kodein میباشد.
شایسته ترین قسمت تزریق ساختار این میباشد که میتوانیم کلیه داده ها مرتبط را در یک جای یعنی اعلان کلاس نگهداری کنیم. در صورتیکه کلاس قابل تزریق باشد و درحالتی که یک سینگلتون باشد یا این که نباشد، شما میتوانید در شکل استعمال از تزریق ساختار، تمامی داده ها را با یک نگاه زود گذر به کلاس ببینید.
اما در حالتیکه شما صاحب کلاس نباشید، نمیتوانید از ماژولها و کدهای تکراری آفریننده گریز نمائید؛ البته اجرا طرز فوق در امر کلیه کلاسهای پایین مالکیت خودتان ایده قابل قبولی به حیث میرسد. به صورت خلاصه میقدرت اعلامکرد که خوب میباشد کدی به طور ذیل داشته باشیم:
@Reusable
class BestPostFinder @Inject constructor() {
...
}
تا این که کدهایی به طور پایین بنویسیم:
@Module
object PostModule {
@JvmStatic @Provides @Reusable
fun provideBestPostFinder() = BestPostFinder()
}
زمانی که آغاز به اضافه کردن تعلقهایی بکنید که خودشان فهرست بزرگی از تعلقها داراهستند، ماژولها به صورت در اختیار گرفتن نشدهای استارت به تعالی شدن مینمایند و خیلی زود به حالت نامناسبی میرسید.
کامپوننتهای فرعی و منطقههای تعریفوتمجید
در شرایطی که «کامپوننتهای فرعی» (Subcomponents) دارای اهمیت بالایی برای شما میباشند، دستور کار فوق ممکن میباشد نیازهای شمارا رفع نکند، البته در اکثر زمان ها پروژهها میتواند راهگشا باشد. در واقع اکثر اوقات موردها کاربرد کامپوننتهای فرعی ضرورتی ندارد؛ ولی به جهت بهبود بی آلایش در سازماندهی تعلقها به کارگیری می گردند. در مستندات (+) ایده به کار گیری از «کامپوننتهای فرعی به مکان کپسولهسازی» مطرح گردیده است؛ البته بخش اعظمی از اشخاص با این ایده مخالف می باشند. اضافه کردن کدهای تکراری تولید کننده که در شکل به کارگیری از تزریق ساختار قابل اجتناب میباشد به سازمانیافتگی بیشتر کد به خصوص در بلند دوران یاری مینماید.
مقصود دیگر کامپوننتهای فرعی، استخراج به حیطههای تعریف و تمجید سفارشی میباشد. با این اکنون، امروزه این اعتقاد و باور وجود داراست که ViewModel و حوزه تعریفی که به طور آزاد ارائه مینمایند، کامپوننتهای فرعی Dagger و منطقههای تعریفشان دیگر ارزشمندی دیرین را ندارند. فعلا اندروید حیطههای Activity و Fragment را به طور فراهم در مشت ما قرار می دهد و از این رو تا وقتیکه تعلقهای سوای حوزه تعریفوتمجید شما در ViewModel قرار دارا هستند، از حوزه تمجید آن به کارگیری مینمایند و از این رو هیچ نگرانی دراین باره نیست.
با این وجود برخی کاربردهای دیگر مانند مواقعی که میخواهیم یک Activity در گراف داشته باشیم، نیز میباشند که ممکن میباشد کامپوننتهای فرعی در آن ها اثر گذار باشند. دقت فرمایید که ما به کارگیری از کامپوننتهای فرعی در همگی جا را کاملا رد نمیکنیم؛ البته اشاره می کنیم که درصورتیکه از آنان تنهاً برای سازماندهی تعلقها یا این که تولید حیطههای تعریف و تمجید سفارشی Activity/Fragment به کارگیری میکنید، احتمالاً مجال معمولیخیس ساختن پیکربندی Dagger را از دست میدهید.
تزریق تعلق در ViewModel با به کارگیری از Dagger ممکن میباشد در صدر بغرنج به لحاظ بیاید. در صورتیکه به کدهای مثال معماری اندروید ارائه گردیده از سوی گوگل (+) نگاه فرمائید مثالی را می یابید که مشتمل بر نقشآفرینی هر دو گزینه ViewModels و Dagger میباشد؛ البته در شرایطی که به مثالهای کامپوننت معماری (+) نگاه فرمایید، GithubBrowserSample (+) را میبینید که آن ها را با هم به کار گیری نموده است. در صورتیکه به نمونه GithubViewModelFactory (+) نگاه فرمائید ممکن میباشد به وحشت بیفتید.
در غایت بایستی اشاره کنیم که طرز آیتم تأکید ما، میتواند در شغل بسیار معمولیخیس از آن چیزی باشد که تصور می کنید. تمامی آن چه نیاز دارید این میباشد که یک annotation به طور Inject@ در خالق ViewModel خویش اضافه فرمایید و ViewModelFactory زیبای پایین این عمل را برای شما اجرا می دهد:
class ViewModelFactory @Inject constructor(
private val viewModel: Lazy
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun create(modelClass: Class) = viewModel.get() as T
}
فعلا میتوانید به آسانی آن ViewModelFactory را تزریق فرمائید و از آن برای ایجاد کرد هر ViewModel که میخواهید به طور تحت منفعت بگیرید:
class BestPostActivity : AppCompatActivity() {
private val viewModel by lazy {
ViewModelProviders
.of(this, injector.bestPostViewModelFactory())
.get(BestPostViewModel::class.java)
}
...
}
با اعتنا بهاین که ما عملاً نیازی به مراقبت ارجاعی برای ViewModel برای دسترسیهای آجل نداریم؛ عالی میباشد به مکان پیچیدن ViewModel در یک Lazy در ViewModelFactory، آن را در یک Provider بپیچید. عامل این که آن را در نوبت ابتدا به آن شکل میپیچیم آن میباشد که از جمله ما یحتاج وجود ندارد ViewModel و تعلقهایش را در حین تغییر تحول جهتگیری، مجدداً ساخت کنیم. چنانچه فکر می کنید این injector تعجب آور میباشد، درپی راجعبه آن بیشتر توضیح دادهایم.
ما قادر خواهیم بود این حالت را با نرم افزار ارائه گردیده در کنفرانس I/O 2018 گوگل (Google I/O 2018 app) مقایسه کنیم. این پیکربندی اندکی متعدد از GithubBrowserSample میباشد. و بی آلایشخیس محسوب میشود؛ البته یک سری factory (به طور یک کدام از برای هر ViewModel) وجود داراست و همچنان غامضخیس از چیزی میباشد که ما جاری ساختن کردهایم.
درصورتی که به پیکربندی ارائه گردیده درین نوشته عشق و علاقهمند میباشید، سفارش میکنیم گزینه ارائه گردیده از سوی Gabor Varadi (+) را نیز پژوهش فرمائید. ما برای این پیکربندی نیز در نرم افزار خویش یک شاخه (+) ساخت و ساز کردهایم. نرم افزار I/O گوگل و هم اینگونه GithubBrowserSample از dagger-android به کار گیری کردهاند، بدین ترتیب پیرو درخصوص آن کلام میکنیم.
dagger-android
بر پایه ی مستندات dagger، علت اساسی پیاده سازی آن بی آلایشسازی طرز تزریق مورد ها متعدد در اکتیویتیها و فرگمانهایی بوده میباشد که در بالا از سوی خویش سیستم ادله مقداردهی اول گردیدهاند، و از این رو قابلیت و امکان به کارگیری از تزریق آفریننده وجود نداشت. این حالت باعث به کدی مانند پایین میشد:
((SomeApplicationBaseType) getContext().getApplicationContext())
.getApplicationComponent()
.newActivityComponentBuilder()
.activity(this)
.build()
.inject(this);
در واقع کد فوق نماد دهنده سناریوی بدترین شرایط میباشد و در اکثر زمان ها مورد ها شرایط بهاین بدی وجود ندارد. البته در هر اکنون این یک حقیقت دارای اعتبار میباشد. به صورت معمول Activity (یا این که Fragment) نباید راجعبه تزریق کننده خودشان اطلاعاتی داشته باشند. با این وجود، ما برای غلبه بر این شرایط به همگی مواقعی که dagger-android ارائه مینماید به خصوص درباره ی به کار گیری از کامپوننتهای فرعی، نیاز نداریم. به مکان آن قادر خواهیم بود از کد ذیل به کارگیری کنیم:
interface DaggerComponentProvider {
val component: ApplicationComponent
}
val Activity.injector get() = (application as DaggerComponentProvider).component
در اینحالت کلاس نرم افزار، DaggerComponentProvider را پیادهسازی مینماید و component را از روش آن ارائه مینماید و به لطف آسانی بیشتراز حد این اکستنشن، قادر خواهیم بود چیزهایی که در یک Activity قرار دارا هستند را با یک ()injector.inject بی آلایش تزریق کنیم. در اینحالت Activity چیزی در باب تزریق کننده خویش نمیداند و تنظیمات Dagger ما نیز همچنان معمولی و فهم آن راحت میباشد.
صحبت نهایی
آنچه درخصوص dagger-android بیشتر آزار میدهد، ترازو دشواری فعال سازی آن میباشد و ادله آوازه منفی Dagger در زمینه ی عدم وضوح نیز همین آیتم میباشد. در شرایطیکه فکرمیکنید در خصوص ترک dagger-android از پروژهتان به دلایل بیشتری نیاز دارید می توانید به موردها مطرح گردیده درین نوشته ی علمی (+) مراجعهنمایید.