github:github.com/wfqdroid/mv…android
先简单介绍一下上面几个git
下面介绍一下项目的架构,就以咱们经常使用的Activity为入口开始介绍github
UI -> ViewModel -> Repository -> NetWork/Dao 箭头是单项的,也就是说,ViewModel持有Repository的引用,反过来没有,不然容易内存泄漏。 网络请求使用的是Retrofit,数据库Dao层这里省略了,最近太忙,等有时间再补充上去。Repository(仓库),负责提供数据,该数据能够从网络去取,也能够从数据库去取, ViewModel持有Repository的引用,也就是能够将仓库的数据拿来本身持有,而后将数据给到UI层。大体的流程就是这样。 下面咱们说一下项目中的细节:数据库
先思考一个问题?在项目中,咱们使用协程,当页面销毁的时候,咱们怎么取消请求? 这里我么使用ViewModel自带的viewModelScope.launch,他会在页面销毁的时候自动取消请求,不过必需要使用AndroidX,咱们能够写一个BaseViewModel编程
open class BaseViewModel:ViewModel() {
fun<T> launch(block: suspend () -> Unit, error: suspend (Throwable) -> Unit, liveData: StateLiveData<T>, isShowLoading:Boolean = true) = viewModelScope.launch {
try {
if(isShowLoading){
liveData.postLoading()
}
block()
} catch (e: Throwable) {
liveData.postError()
error(e)
}finally {
liveData.postSuccess()
}
}
}
class ArticleViewModel(private val respository: ArticleRepository) : BaseViewModel() {
val data = StateLiveData<List<Data>>()
fun getArticle() {
launch({
respository.getArticle()?.let {
data.postValueAndSuccess(it)
}
}, {
}, data)
}
}
复制代码
StateLiveData是一个由状态的LiveData,这样咱们能够在BaseViewModel的launch里面直接发送loading等用于界面交互bash
class StateLiveData<T> : MutableLiveData<T>() {
enum class State {
Idle, Loading, Success, Error
}
val state = MutableLiveData<State>()
init {
initState()
}
fun postValueAndSuccess(value: T) {
super.postValue(value)
postSuccess()
}
private fun initState() {
state.postValue(State.Idle)
}
fun postLoading() {
state.postValue(State.Loading)
}
fun postSuccess() {
state.postValue(State.Success)
}
fun postError() {
state.postValue(State.Error)
}
}
复制代码
咱们如何根据服务端的状态码来进行不一样操做? 这里咱们采用在Retrofit的Call对象上面扩展了一个await的函数的方式,之后本身的模块的NetWork直接继承BaseNetWork便可网络
open class BaseNetwork {
suspend fun <T> Call<T>.await(): T {
return suspendCoroutine {
enqueue(object : Callback<T> {
override fun onFailure(call: Call<T>, t: Throwable) {
it.resumeWithException(t)
}
override fun onResponse(call: Call<T>, response: Response<T>) {
if (response.isSuccessful) {
val body = response.body()
if (body != null) {
body as BaseRes<T>
if (body.errorCode == 0)
it.resume(body)
else if(body.errorCode == 100){
// 比方说登陆超时等
}else{
it.resumeWithException(RuntimeException(body.errorMsg))
}
} else {
it.resumeWithException(RuntimeException("response body is null"))
}
} else {
}
}
})
}
}
}
复制代码
github:github.com/wfqdroid/mv…架构
参考:juejin.im/post/5ceddb… blog.csdn.net/guolin_blog… developer.android.com/topic/libra…异步