در برنامه نویسی اندروید، مدیریت وابستگیها میتواند یک نگرانی بزرگ باشد. اگر از Dagger2 در پرژوههای خود استفاده کرده باشید، میدانید که برای هر پروژه به کدهای تکراری بسیار زیادی نیاز دارید. با اضافه کردن ویژگیهای جدید به پروژه، این کدهای تکراری بیشتر هم میشوند و شما مجبور هستید برای هر ماژول جدید، کدهای تکراری بنویسید. Dagger2 برای زبان جاوا نوشته شده است و Koin برای زبان کاتلین. همچنین شما میتوانید از هر دو کتابخانه در پروژهی کاتلین خود استفاده کنید. اما استفاده از Koin در جاوا میتواند برای شما مشکل ساز باشد. یک نکتهی قابل توجه در مقایسه Koin و Dagger این است که Dagger2 یک Dependency Injection است، اما Koin یک Service Locator میباشد. طی چند سال گذشته، عمدتا از Dagger2 برای تزریق وابستگی استفاده میشد. در این مقاله این به مقایسه Koin و Dagger خواهیم پرداخت. با ما همراه باشید.
اگر شما هم به برنامه نویسی اندروید علاقهمندید پیشنهاد میکنیم به صفحات دورههای آموزش فلاتر و آموزش اندروید سر بزنید.
Koin چیست؟
Koin یک فریمورک سبک تزریق وابستگی برای توسعه دهندگان کاتلین است. Koin فقط با استفاده از عملکرد کاتلین نوشته شده است: no proxy, no code generation, no reflection.
ما به منظور مقایسه Koin و Dagger، بر روی پروژهای تمرکز خواهیم کرد که ابتدا با Dagger2 و سپس با Koin پیاده سازی شده است. معماری این پروژه MVVM است و در آن از Retrofit و LiveData استفاده شده است. این پروژه دارای یک اکتیویتی، چهار فرگمنت، پنج ViewModel، یک Repository و یک web service است، بنابراین در این پروژه فقط پایههای اصلی طراحی شده است.
پکیج DI را در تصویر زیر مشاهده کنید. عکس سمت راست پیاده سازی برای Dagger و عکس سمت راست برای Koin میباشد.
همانطور که در تصویر مشاهده میکنید، برای استفاده از dagger2 شما به فایلها و کدهای زیادی نیاز دارید. در صورتی که همین کار با Koin خیلی سادهتر شده و فایلها و کدهای بسیار کمتری لازم دارد.
مقایسه تعداد خطوط کد در koin و dagger بعد از کامپایل شدن
برای به دست آوردن این اعداد از آمار استفاده کردیم. نتیجه جالب است.
این تعداد کد قبل و بعد از کامپایل میباشد. همانطور که میبینید تعداد خط کد ایجاد شده توسط dagger دو برابر بیشتر از Koin است.
مقایسه آماری در گوگل را در تصویر بالا مشاهده میکنید.
از مشاهدات آماری فوق کاملاً مشخص است که Koin امتیاز بیشتری نسبت به Dagger2 کسب میکند.
مقایسه Koin و Dagger در زمان build شدن
برخی توسعه دهندگان، Koin را بر Dagger2 ترجیح میدهند. آنها معتقد هستند که کار با Dagger2 دشوار میباشد اما ممکن است این مشکل، یک مسئلهی کوچک باشد. Dagger2 به دلیل کدهای زیاد تولید شده، برای توسعه دهندگان مشکل ایجاد میکند و رفع این مشکل، یک کابوس است. علاوه بر این، یادگیری Dagger2 برای تازهکارها دشوار میباشد، بنابراین اگر کسی به پروژه یا تیم شما بپیوندد باید زمان زیادی را صرف یادگیری Dagger2 کند.
چرا از Koin استفاده کنیم؟
No Reflection
کد اضافی تولید نمیکند.
برای انجام یک تزریق ساده نیازی به نوشتن کد زیاد نیست.
ادغام و نگهداری بسیار آسان است.
پروکسی رایگان است.
نیازی به کد تکراری و کار اضافی نیست.
تست با Koin بسیار آسان میباشد.
راهاندازی Dagger
مورد دیگر راه اندازی این کتابخانهها است. فرض کنید میخواهید از dagger و MVVM استفاده کنید. برای راه اندازی این کتابخانهها به این صورت عمل میکنیم:
پس از ایجاد ماژولها و اجزای سازنده، باید Dagger را در کلاس Application یا متدهای دیگر initialize کنید.
Class MyApplication : Application(), HasActivityInjector {
@Inject
lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Activity>
override fun activityInjector() = dispatchingAndroidInjector
fun initDagger() {
DaggerAppComponent
.builder()
.application(this)
.build()
.inject(this)
}
}
به همین ترتیب، در همه اکتیویتیها یا در BaseActivity، باید HasSupportFragmentInjector را پیادهسازی کنیم و DispatchingAndroidInjector را تزریق کنیم.
برای ViewModelها، باید ViewModelFactory را در BaseFragment تزریق کنیم و همچنین Injectable را پیاده سازی کنیم.
برای هر ViewMode Fragment و Activity باید نحوهی تزریق آنها را به DI اطلاع دهیم. همانطور که مشاهده میکنید ActivityModule ،FragmentModule و ViewModelModule را داریم.
ActivityModule:
@Module
abstract class ActivityModule {
@ContributesAndroidInjector(modules = [FragmentModule::class])
abstract fun contributeMainActivity(): MainActivity
//Add your other activities here
}
برای فرگمنتها:
@Module
abstract class FragmentModule {
@ContributesAndroidInjector
abstract fun contributeLoginFragment(): LoginFragment
@ContributesAndroidInjector
abstract fun contributeRegisterFragment(): RegisterFragment
@ContributesAndroidInjector
abstract fun contributeStartPageFragment(): StartPageFragment
}
و برای ViewModelها:
@Module
abstract class ViewModelModule {
@Binds
abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory
@Binds
@IntoMap
@ViewModelKey(loginViewModel::class)
abstract fun bindLoginFragmentViewModel(loginViewModel: loginViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(StartPageViewModel::class)
abstract fun bindStartPageViewModel(startPageViewModel: StartPageViewModel): ViewModel
......
}
بنابراین شما باید با افزودن فرگمنتها، اکتیویتیها و ViewModelهای جدید به ماژولهای DI اهمیت دهید، همچنین باید به همهی توسعه دهندگان بگویید تا به این مسئله اهمیت دهند.
راه اندازی Koin
همانطور که میدانید ابتدا باید وابستگی Koin را اضافه کنیم.
این نسخه از Koin با ViewModel استفاده میشود، وابستگیهای دیگری نیز برای استفاده از Koin وجود دارد، اما ما میخواهیم از آن با MVVM استفاده کنیم.
پس از افزودن وابستگی Koin، ما میتوانیم اولین ماژول خود را پیاده سازی کنیم، دقیقاً مانند Dagger میتوانیم همهی ماژولها را در یک فایل جداگانه پیاده سازی کنیم، اما به دلیل سادگی کد، تصمیم گرفتیم همهی ماژولها را در یک فایل پیاده سازی کنیم. بعداً میتوانید آنها را جدا کنید.
ابتدا باید برخی از نکات مفید دربارهی سینتکس koin را بدانیم:
()get: برای حل یک نمونه در یک ماژول Koin، فقط از تابع ()get، به عنوان مولفهی مورد نیاز استفاده کنید. تابع ()get معمولا برای تزریق مقادیر constructor در constructor استفاده میشود.
()factory: با هر بار درخواست از مولفهی ()factory، شما نمونه جدیدی را از آن دریافت خواهید کرد.
()single: یک Singleton را برای شما فراهم میکند.
name = : برای نامگذاری تعاریف استفاده میشود. این مورد زمانی لازم است که بخواهید چندین نمونه از یک کلاس را با انواع مختلفی داشته باشید.
appinjector.kt:
package com.7learn.sevenlearn.di
import com.farshidabz.gettingstartkoin.data.remote.ImagesApi
import org.koin.dsl.module
import retrofit2.Retrofit
private val retrofit: Retrofit = createNetworkClient()
private val IMAGES_API: ImagesApi = retrofit.create(ImagesApi::class.java)
val networkModule = module {
single { IMAGES_API }
}
کلاس viewModels را به عنوان viewModel در یک ماژول تعریف میکنیم. Koin یک ViewModel به چرخهی حیات ViewModelFactory میدهد و به اتصال آن به current component کمک میکند.
همانطور که میبینید ما یک متد ()get به سازنده LoginFragmentViewModel داریم. این تابع ساخت نمونهای از LoginFragmentViewModel را تصمیم گیری میکند. اینجا AuthRepo است.
در کلاس Application خود در متد ()onCreate کد را بنویسید:
در اینجا به سادگی متد startKoin را صدا میکنیم و در یک context و لیستی از ماژولهایی که میخواهیم Koin را با آنها initialize کنیم، قرار میدهیم.
استفاده از ViewModel بسیار ساده است. در کلاس View خود (Fragment، Activity) این مورد را اضافه کنید:
private val startPageViewModel: StartPageViewModel by viewModel()
با این کد، koin یک شی از StartPageViewModel برای شما ایجاد میکند و startPageViewModel را با آن فراخوانی میکند. اکنون میتوانید از ViewModel خود در View استفاده کنید.
جمع بندی
در این مقاله، به مقایسه Koin و Dagger پرداختیم و آموختیم که koin مزایای خیلی بیشتری نسبت به dagger دارد و کار با آن بسیار ساده است. در صورتی که کار با Dagger بسیار سخت و وقت گیر است. امیدواریم از این مقاله لذت برده باشید. اگر دربارهی مقایسه Koin و Dagger سوال و نظری دارید، خوشحال میشویم که آن را با ما و کاربران سون لرن به اشتراک بگذارید.
اگر به یادگیری بیشتر در زمینهی برنامه نویسی اندروید علاقه داری، با شرکت در دوره آموزش برنامه نویسی اندروید در کمتر از یکسال به یک توسعهدهنده اندروید همه فن حریف تبدیل میشوی که آمادهی استخدام، دریافت پروژه و حتی پیادهسازی اپلیکیشن خودت هستی.
۴ دیدگاه
۱۴ دی ۱۴۰۰، ۰۸:۲۵
تصوریر سمت راست dagger و تصویر سمت راست koin :| سمت راست متعلق به هردوعه :|
پوریا۱۴ بهمن ۱۳۹۹، ۰۹:۴۱
سلام
مقاله عالی بود
تشکر از شما
وحید گروسی۰۵ بهمن ۱۳۹۹، ۱۳:۰۴
سلام وقتتون بخیر ممنون از شما برای تهیه این محتوا
اخیرا کتابخانه ای به نام Dagger Hiltمنتشر شده که به مراتب راحتتر از این مورد هست لطفاْ این مورد رو هم بررسی کنید
نازنین کریمی مقدم۰۵ بهمن ۱۳۹۹، ۱۸:۱۷
درود.
حتما، یه مقاله مقایسه dagger و hilt هم در تقویم محتوایی آینده مون قرار داره.
ممنون که با ما همراه هستید.