在以前使用MVP的同窗,若是你使用過依賴注入框架Dagger的話,你就會發現,它是多麼的難用,這裏對Dagger的使用就不作介紹了。咱們來一塊兒學習在kotlin上的新的依賴注入框架koinjava
本文使用kotlin + Jetpackandroid
按照谷歌的建議,一個APP,應該包含UI層,ViewModel層,Repository層,這裏簡單介紹一下,UI持有ViewModel的引用,ViewModel持有Repository的引用,Repository持有數據庫Dao層和網絡Network層數據庫
引入依賴: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