تزریق وابستگی چیست؟
تزریق وابستگی مبتنی بر مفهومی به نام وارونگی کنترل (Inversion of Control) است. این مفهوم به این معنی است که یک کلاس باید وابستگی های خود را از کلاس خارجی دریافت کند نه اینکه آنها را در کلاس فرا خوانی کند.
تزریق وابستگی در Android با استفاده از Dagger2
Dagger2 یک framework تزریق وابستگی کاملاً استاتیک و کامپایل شده است که بر اساس درخواست مشخصات جاوا 330(JSR) مورد استفاده برای اندروید و جاوا است. از کد generation استفاده می کند و مبتنی بر annotation نویسی است. کدی که تولید شده برای خواندن و debug بسیار آسان است. نسخه قبلی daggerتوسط کمپانی Square ایجاد شد و اکنون توسط گوگل نگهداری و توسعه داده میشود.
سه قسمت اصلی dagger که با آنها آشنا میشیم:
1) Dependency Provider
Dependency Consumer (2
Component (3
1- Dependency Provider
object هایی که dependencies نامیده می شوند را فراهم می کند. کلاسی که وظیفه تأمین وابستگی را بر عهده دارد،با annotation(انوتیشن) Module و متد هایی که وابستگی (object) ها را در این کلاس ایجاد می کند با انوتیشن provides مشخص میشود
2-Dependency Consumer
كلاسی است كه در آن ما باید object ها را معرفی كنیم. اما نیازی نیست که آن را با کلمه کلیدی جدید معرفی کنیم. حتی لازم نیست که به عنوان یک argument به آن برسید. اما dagger وابستگی را فراهم می کند و برای این کار فقط باید تعریف object را با انوتیشن Inject@ بنویسیم.
3. Component
یک interface که به عنوان واسط بینdependency consumer و dependency provider است و با انوتیشن Component@ مشخص میشود.
Dependencyهای dagger2
در فایل build.gradle پروژه dependency های زیر را وارد کنید
ext.dagger2_version = '2.24'
// Basic Dagger 2 (required)
implementation "com.google.dagger:dagger:$dagger2_version"
kapt "com.google.dagger:dagger-compiler:$dagger2_version"
// dagger.android package (optional)
implementation "com.google.dagger:dagger-android:$dagger2_version"
kapt "com.google.dagger:dagger-android-processor:$dagger2_version"
// Support library support (optional)
kapt "com.google.dagger:dagger-android-support:$dagger2_version"
Dependencyهای Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.6.1'
implementation 'com.squareup.retrofit2:retrofit-converters:2.6.1'
implementation 'com.squareup.retrofit2:retrofit-adapters:2.6.1'
implementation 'com.squareup.retrofit2:converter-gson:2.6.1'
یک کلاس به نام APIModule می سازیم که کلاس provider ما هست و کدهای آن به صورت زیر است
class APIModule constructor(baseURL:String) {
var baseURL:String?=""
init {
this.baseURL = baseURL
}
@Singleton
@Provides
fun provideOKHttpClient():OkHttpClient{
return OkHttpClient.Builder()
.readTimeout(1200,TimeUnit.SECONDS)
.connectTimeout(1200,TimeUnit.SECONDS)
.build()
}
@Singleton
@Provides
fun provideGSON(): GsonConverterFactory {
return GsonConverterFactory.create()
}
@Singleton
@Provides
fun provideRetrofit(gsonConverterFactory: GsonConverterFactory,okHttpClient: OkHttpClient):Retrofit{
return Retrofit.Builder()
.baseUrl(baseURL)
.addConverterFactory(gsonConverterFactory)
.client(okHttpClient)
.build()
}
@Provides
fun provideRetroRepository():RetrofitRepository{
return RetrofitRepository()
}
}
یک interface میسازیم و اسمش را APIComponent میگذاریم در پایین کدهایش را می بینید.
@Singleton
@Component(modules = [AppModule::class,APIModule::class])
interface APIComponent {
fun inject(retrofitRepository: RetrofitRepository)
fun inject(retroViewModel: RetroViewModel)
fun inject(retroFragment: RetroFragment)
fun inject(retroViewModelFactory:RetroViewModelFactory)
}
در خط دوم گفتیم که این component از چه modules های استفاده کند.
DaggerComponent Initialization
DaggerComponent را در کلاس Application تعریف و Initiate کنید تا در سراسر برنامه در دسترس باشد. در کلاس application متد زیر را بنویسید
fun initDaggerComponent():APIComponent{
apiComponent = DaggerAPIComponent
.builder()
.aPIModule(APIModule(APIURL.BASE_URL))
.build()
return apiComponent
}
Dependency Consumer
RetroRepository کلاسی است که با استفاده از انوتیشن Inject،تزریق وابستگی را انجام میدهد.
@Inject
lateinit var retrofit: Retrofit
کد های کلاس RetroRepository به صورت زیر می باشد:
class RetrofitRepository {
lateinit var apiComponent: APIComponent
var postInfoMutableList: MutableLiveData<List<PostInfo>> = MutableLiveData()
@Inject
lateinit var retrofit: Retrofit
init {
/* apiComponent = DaggerAPIComponent
.builder()
.aPIModule(APIModule(APIURL.BASE_URL))
.build()
apiComponent.inject(this)*/
var apiComponent :APIComponent = MyRetroApplication.apiComponent
apiComponent.inject(this)
}
fun fetchPostInfoList(): LiveData<List<PostInfo>> {
var apiService:APIService = retrofit.create(APIService::class.java)
var postListInfo : Call<List<PostInfo>> = apiService.makeRequest()
postListInfo.enqueue(object :Callback<List<PostInfo>>{
override fun onFailure(call: Call<List<PostInfo>>, t: Throwable) {
Log.d("RetroRepository","Failed:::"+t.message)
}
override fun onResponse(call: Call<List<PostInfo>>, response: Response<List<PostInfo>>) {
var postInfoList = response.body()
postInfoMutableList.value = postInfoList
}
})
return postInfoMutableList
}
}
کلاس ViewModelFactory
برای انتقال آرگومانها به ViewModel از کلاس view model factory استفاده میکنیم. در این برنامه RetroRepository در ViewModelProvider تزریق می شود و به عنوان آرگومان به ViewModel ارسال می شود.
class RetroViewModelFactory : ViewModelProvider.Factory {
lateinit var apiComponent: APIComponent
@Inject
lateinit var retrofitRepository: RetrofitRepository
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
// initDaggerComponent()
var apiComponent :APIComponent = MyRetroApplication.apiComponent
apiComponent.inject(this)
if (modelClass.isAssignableFrom(RetroViewModel::class.java)) {
return RetroViewModel(retrofitRepository) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
{
کلاس RetroViewModel
RetrofitRepository به عنوان آرگومان وبدونه این که object از آن بسازیم منتقل می شود.
class RetroViewModel(retrofitRepository: RetrofitRepository): ViewModel() {
lateinit var retrofitRepository:RetrofitRepository
var postInfoLiveData: LiveData<List<PostInfo>> = MutableLiveData()
init {
this.retrofitRepository = retrofitRepository
fetchPostInfoFromRepository()
}
fun fetchPostInfoFromRepository(){
postInfoLiveData = retrofitRepository.fetchPostInfoList()
}
کلاس APIURL آدرس api هارا از این کلاس میگیریم(BaseUrl)
class APIURL {
companion object {
const val BASE_URL = "https://jsonplaceholder.typicode.com/"
}
}
کلاس Service Interface که یک interface است و حاوی api های مورد نیاز است
interface APIService {
@GET("posts")
fun makeRequest(): Call<List<PostInfo>>
}
سورس این آموزش رو میتونید از لینک زیر دانلود کنید.
https://github.com/maysambabaei/Dagger2-retrofit-mvvm-kotlin/tree/master
سوالات و مشکلات خود را در بخش نظرات برای ما ارسال کنید.
برای افزودن دیدگاه خود، نیاز است ابتدا وارد حساب کاربریتان شوید