讓我們來聯手打造屬於自己的MVVM

前言

說到MVVM,大家肯定能想到JetPack中的DataBinding,一個實現數據和UI綁定的框架,構建MVVM模式的一個工具。然而,在實際的項目使用中就是:“一千個讀者就有一千個哈姆雷特”。對於一些新手來說,可能不理解它是怎麼劃分的,今天就讓我們一起來打造一個屬於自己的MVVM吧。

MVVM

MVVM全稱Model View ViewModel,其優點:低耦合,數據和業務邏輯處於一個獨立的ViewModel中,ViewModel只需要關注數據和業務邏輯,不需要和View層打交道。等等(這裏就不詳細說明了)
結構圖
(結構圖,個人理解)

Model

Model主要是封裝數據存儲或操作的一些邏輯。
項目劃分: 例如:網絡請求、數據庫操作等。

View

View用於處理界面的邏輯且不參與業務邏輯相關的操作,只負責顯示由ViewModel提供的數據,View層不做任何業務邏輯、不涉及操作數據、不處理數據,UI和數據嚴格的分開,對應於Activity、Fragment和XML。
項目劃分:(Activity、Fragment)只做數據顯示。

ViewModel

ViewModel是處理業務邏輯和業務數據相關的中樞,ViewModel層不會持有任何控件的引用。
項目劃分:對Model層返回的數據做處理,並將數據通過JetPack部分框架(如DataBinding、LiveData)去刷新UI。

概念已經分析的差不多了,剩下的就可以動動手開搞了。
首先封裝Model:
可以根據上面分析那樣去封裝,比如封裝些網絡請求實例對象,數據庫實例對象,gson數據等。

open class BaseModel {

    val apiService : ApiService by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
        RetrofitManager.create(ApiService::class.java)
    }

    val gson : Gson by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
        GsonBuilder().disableHtmlEscaping().create()
    }

    fun getMap(): TreeMap<String, String> {
        return TreeMap(Comparator { o1, o2 ->
            o1.compareTo(o2) //用正負表示大小值
        })
    }


    fun TreeMap<String,String>.toJson() : String{
        return gson.toJson(this)
    }

    fun String.getRequestBody() : RequestBody {
        return this.toRequestBody("application/json;charset=UTF-8".toMediaType())
    }

}

緊接着就是ViewModel,因爲我用的RxJava,對RxJava進行了部分封裝,還關聯的頁面的生命週期,頁面銷燬的時候可以自動註銷頁面的訂閱。

open class BaseViewModel : ViewModel(),IViewModel {

    val errorLiveData: MutableLiveData<String> = MutableLiveData()
    private var compositeDisposable = CompositeDisposable()

    override fun onCreate(owner: LifecycleOwner) {
        //創建
    }

    override fun onDestroy(owner: LifecycleOwner) {
        //銷燬
        detachView()
        //移除生命週期監聽觀察者
        owner.lifecycle.removeObserver(this)
    }

    override fun onLifecycleChanged(owner: LifecycleOwner, event: Lifecycle.Event) {
        //生命週期狀態改變
    }

    //泛型可以爲 <T : BaseBean> ,也可以爲 <T : List<BaseBean>>
    //此處爲Observable的拓展函數,你也可以改爲Flowable的拓展函數
    fun <T : BaseBean> Observable<T>.onResult(
        next: Consumer<T>,
        error: Consumer<Throwable> = Consumer {
            errorLiveData.postValue(it.message)
        }
    ) {
        val disposable = this.subscribeOn(Schedulers.io())
            .unsubscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(next, error)
        addSubscription(disposable)
    }

    private infix fun <T : BaseBean> Observable<T>.onResult(
        next: Consumer<T>
    ) {
        this.onResult(next,Consumer {
            errorLiveData.postValue(it.message)
        })
    }

    fun <T : BaseBean> Observable<T>.onResult(
        next : (T) -> Unit
    ){
        this onResult Consumer {
            //這裏進行返回判斷
            if (!TextUtils.equals(it.errorCode,"0")){
                errorLiveData.value = it.errorMsg
                return@Consumer
            }
            next(it)
        }
    }


    private fun addSubscription(disposable: Disposable) {
        compositeDisposable.add(disposable)
    }

    private fun detachView() {
        //保證activity結束時取消所有正在執行的訂閱
        if (!compositeDisposable.isDisposed) {
            compositeDisposable.clear()
        }
    }
}

最後就是View了,這裏的封裝只跟上面的關聯。

open class BaseActivity : AppCompatActivity() {

    @MainThread
    fun <VM : BaseViewModel> createVModel(clazz: Class<VM>): VM {
        val viewModel = ViewModelProvider(this)[clazz]
        //綁定頁面的生命週期
        lifecycle.addObserver(viewModel)
        //綁定默認的錯誤回調
        bindErrorData(viewModel)
        return viewModel
    }

    private fun bindErrorData(vm : BaseViewModel){
        vm.errorLiveData.observe(this, Observer {
            onError(it)
        })
    }

	//公開個錯誤方法讓子類回調處理
    open fun onError(t:String){
        if (!TextUtils.isEmpty(t)){
            Toast.makeText(this,t,Toast.LENGTH_SHORT).show()
        }
    }
}

篇幅問題,我這裏就不貼出子類代碼了,完整的代碼在github上,如果覺得對你有點幫助的可以點給免費的star。

項目地址

好了,說得再多也不如自己動手試試,不管誰的代碼,自己寫了,掌握了就是自己的代碼。如有問題,歡迎指出。
github: https://github.com/cithrf/RxDemo

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章