使用Koin來完成Kotlin的依賴注入

在以前使用MVP的同窗,若是你使用過依賴注入框架Dagger的話,你就會發現,它是多麼的難用,這裏對Dagger的使用就不作介紹了。咱們來一塊兒學習在kotlin上的新的依賴注入框架koinjava

本文使用kotlin + Jetpackandroid

按照谷歌的建議,一個APP,應該包含UI層,ViewModel層,Repository層,這裏簡單介紹一下,UI持有ViewModel的引用,ViewModel持有Repository的引用,Repository持有數據庫Dao層和網絡Network層數據庫

使用Koin

引入依賴:api

def retrofit_version = '2.6.0'
def moshiVersion = '1.8.0'
def koin_version = "2.0.1"
def viewmodel_ktx = '2.2.0-alpha03'
def kotlinCoroutineVersion = "1.0.1"

// retrofit以及moshi轉換,將響應的結果解析成對象
implementation "com.squareup.retrofit2:retrofit:${retrofit_version}"
implementation "com.squareup.retrofit2:converter-moshi:$retrofit_version"

// moshi 解析JSON
implementation "com.squareup.moshi:moshi-kotlin:$moshiVersion"
kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshiVersion"

// koin 依賴注入
implementation "org.koin:koin-android:$koin_version"
implementation "org.koin:koin-android-viewmodel:$koin_version"

// 可以使用協程並能夠觀察生命週期的ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$viewmodel_ktx"

// 協程
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinCoroutineVersion"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinCoroutineVersion"
    
    
複製代碼

看完所須要的依賴,有的同窗可能會問,爲何沒有Retrofit的adapter,像implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'等,這裏想介紹的是協程,Retrofit的2.6.0版本已經開始支持suspend函數了。bash

Koin的使用須要咱們在Application裏面進行註冊:網絡

override fun onCreate() {
        super.onCreate()
        startKoin{
            androidLogger()
            androidContext(this@BaseApplication)
            modules(listOf(repoModule, viewmodelModule, networkModule))
        }
    }
複製代碼

在Application裏面,註冊了三個module,分別對應的是咱們的倉庫層,ViewModel層,網絡層框架

新建文件夾di,咱們將三個module寫在這裏ide

// NetworkModule.kt
val api = ApiRepo.api
val networkModule = module {
    single {
        api
    }
}

// RepoModule.kt
val repoModule = module {
    single {
        MainRepo(get())
    }
}

// ViewModelModule.kt
val viewmodelModule = module {
    viewModel {
        MainViewModel(get())
    }
}
// ApiRepo.kt
object ApiRepo {
    private val okHttpClient = OkHttpClient.Builder()
        .build()

    private val retrofit = Retrofit.Builder()
        .client(okHttpClient)
        .baseUrl("your baseurl")
        .addConverterFactory(MoshiConverterFactory.create())
        .build()

    val api : Api = retrofit.create(Api::class.java)
}

// Api.kt
interface Api {
    @GET("")
    suspend fun getCountryData(): BaseModel<List<CountryModel>>
}

複製代碼

上面的代碼很簡單,咱們每次新建的ViewModel,Repository以後,在viewmodelModule.kt和RepoModule.kt分別進行聲明便可,咱們看到,聲明ViewModel的時候使用的是MainViewModel(get()),這裏多了個get(),爲何?由於咱們的ViewModel層是要持有倉庫層的引用的,使用get()的話,就會去在全部的注入的類裏面去尋找咱們須要的,簡單吧。函數

咱們看到在API裏,咱們在調用接口的時候使用了suspend關鍵字,返回的結果也再也不是一個Call了,咱們在使用的時候只須要開一個協程,便可拿到咱們須要的數據,而後使用LiveData就能將數據發送到咱們的UI上學習

下面咱們看具體的代碼:

// MainRepo.kt
class MainRepo(private val api:Api) {
    suspend fun getCountryData() : BaseModel<List<CountryModel>> = api.getCountryData()
}

// MainViewModel.kt
class MainViewModel(private val repo: MainRepo) : ViewModel() {

    var countryLiveData = MutableLiveData<BaseModel<List<CountryModel>>()
    fun getCountryData() {
    // 在Activity銷燬的時候,這裏會自動關閉
        viewModelScope.launch {
            countryLiveData.value = fetch(repo.getCountryData())
        }
    }
}


class MainActivity : AppCompatActivity() {
    
    // 只須要經過koin的by viewModel就能夠拿到咱們註冊的MainViewModel了
    private val mainViewModel by viewModel<MainViewModel>()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        mainViewModel.getCountryData()
        mainViewModel.countryLiveData.observe(this, Observer {
            // do something
        })
        
    }
}
複製代碼

總結

  • 使用了koin,在業務複雜的時候就方便了許多,不再用經過構造函數傳來傳去了

  • Retrofit的2.6.0版本已經默認支持協程了,可能有些同窗會以爲,就使用一個suspend的話,有些異常該怎麼處理,其實咱們在ViewModel層,在調用倉庫層的方法的時候,可使用一個try-catch便可去處理異常了,或者來一個BaseViewModel,統一處理

  • 使用LiveData + ViewModel + coroutines,在請求網絡的時候就不用擔憂切換線程啦,頁面銷燬時如何取消請求啦等問題了,固然,ViewModel要使用上面gradle裏面依賴的ViewModel

相關文章
相關標籤/搜索