MVVM架构:LiveData,ViewModel,kotlin,kotlin协程,DataBinding等

MVVM

github:github.com/wfqdroid/mv…android

所使用到的技术:LiveData,ViewModel,kotlin,kotlin协程,DataBinding等

先简单介绍一下上面几个git

  • LiveData:见名知意,观察订阅模式,用于响应式编程,咱们都知道RxJava的强大,可是LiveData相比于其,根本 不用管生命周期,应用会在页面"活着"的时候将数据同时到页面,当页面不可见或者销毁的时候,数据就中断响应,具体的使用参照项目代码
  • ViewModel 官方给出的介绍是,持有页面须要的数据,当手机旋转的时候,不会销毁数据。同时也是MVVM架构的VM层
  • kotlin/kotlin协程 kotlin毋庸置疑,作Android的几乎都在学习,kotlin1.3以后,协程已经成了稳定版本,咱们能够放心使用。使用协程以后,咱们几乎能够不用管线程, 它比线程要轻量,与LiveData配合使用,当网络响应了咱们数据的时候,不须要使用Handler作线程切换,也不须要使用RxJava的操做符作切换了。咱们以前的开发,习惯了 接口回调数据了,而kotlin协程,则可使用同步的方式作异步的操做,代码简洁高效
  • DataBinding 谈到MVVM,不少人就离不开databinding,mvvm是一种思想,databing只是google给咱们的一个工具,用来实现响应式编程,双向绑定的。

下面介绍一下项目的架构,就以咱们经常使用的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…异步

相关文章
相关标签/搜索