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…異步

相關文章
相關標籤/搜索