在以前使用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