让我们来联手打造属于自己的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

猜你喜欢

转载自blog.csdn.net/qq_38345791/article/details/106825566