Android架构模式mvc,mvp,mvvm的优缺点总结与应用中mvvm接入教程

首先谈下Android种常见的几种项目的架构模式的优缺点:

一.MVC (Model-View-Presenter):作用是数据模型与业务和展示逻辑解耦,在客户端应用开发中,就是将模型(M-数据)、视图(V-页面)之间实现代码分离,松散耦合,使之成为一个更容易开发、维护和测试的客户端应用程序。他们的调用流程是:

  1. View 传送指令到 Controller ;

  2. Controller 完成业务逻辑后,要求 Model 改变状态 ;

  3. Model 将新的数据发送到 View,用户得到反馈。

 优点是:耦合性低,视图层和业务层分离,这样就允许更改视图层代码而不用重新编译模型和控制器代码。重用性高

 缺点是:view和vontroller连接过于紧密,视图没有控制器的存在,其应用是很有限的,反之亦然,这样就妨碍了他们的独立重用。

二.MVP:(Model-View-Presenter)是MVC的改良模式,由IBM的子公司Taligent提出。和MVC的相同之处在于:Controller/Presenter负责业务逻辑,Model管理数据,View负责显示只不过是将 Controller 改名为 Presenter,同时改变了通信方向。

mvp的互相调用特点是:1.View 与 Model 不通信,都通过 Presenter 传递。Presenter完全把Model和View进行了分离,主要的程序逻辑在Presenter里实现。2.逻辑代码都在presenter中

mvp优点:

  1. 模型与视图完全分离,我们可以修改视图而不影响模型;
  2. 可以更高效地使用模型,因为所有的交互都发生在一个地方——Presenter内部;
  3. 我们可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑。这个特性非常的有用,因为视图的变化总是比模型的变化频繁; 

mvp缺点: view和presenter使用接口量很大,视图和Presenter的交互会过于频繁,一旦视图变更了,presenter也需要变更。

三.MVVM(Model-View-ModelView) :MVVM是由微软提出来的,MVVM相对于MVC的改进是对VM/P和view做了双向的数据和命令绑定。

优点:利用观察者模式和数据绑定,减少写回调接口的过程,代码和逻辑和更简洁清晰

缺点:随着后期功能不断增加,viewmodel中的代码量会越来越多。

项目中接入mvvm的代码示例:

第一步:项目的build.gradle文件中加入如下dataBinding依赖和打开dataBinding开关:

android {
  '''
  dataBinding {
        enabled = true
    }
  ...

}



dependencies {

    // databinding库
    kapt "com.android.databinding:compiler:$gradlePluginVersion"
}

第二步:建立自己的model,viewmodel,view三个层的目录,然后分别创建各个层下面对应业务的文件,

首先从model层开始:和mvp,mvc一样,model层里面的类负责封装解析json数据的模型类,

我这里在model目录下创建了一个WallpaperlistBeanF的实体类:

class WallpaperlistBeanF(
        @SerializedName("code") var code: Int,
        @SerializedName("data")var data: List<Data>,
        @SerializedName("msg") var msg: String

) : Serializable {
        data class Data(
                @SerializedName("id") var id: Int,
                @SerializedName("wname") var wname: String,
                @SerializedName("wcategory") var wcategory: String,
                @SerializedName("wurl_preview") var wurl_preview: String,
                @SerializedName("wurl_middle") var wurl_middle: String,
                @SerializedName("wurl_master") var wurl_master: String,
                @SerializedName("whot") var whot: Int,
                @SerializedName("wjurisdiction") var wjurisdiction: Int,
                @SerializedName("wpush_date") var wpush_date: String,
                @SerializedName("wadvert") var wadvert: Boolean,
                @SerializedName("wis_dynamic") var wis_dynamic: Boolean,
                @SerializedName("wcreate_date") var wcreate_date: String,
                @SerializedName("wshow") var wshow: Boolean

        ):Serializable {
                override fun toString(): String {
                        return "Data(id=$id, wname='$wname', wcategory='$wcategory', wurl_preview='$wurl_preview', wurl_master='$wurl_master', whot=$whot, wjurisdiction=$wjurisdiction, wpush_date='$wpush_date', wadvert=$wadvert, wis_dynamic=$wis_dynamic, wcreate_date='$wcreate_date', wshow=$wshow)"
                }
        }

        override fun toString(): String {
                return "WallpaperlistBeanF(code=$code, data=$data, msg='$msg')"
        }
}

接下来写viewmodel层的代码:

先贴一段我自己做的网络请求方面的各种returnCode的封装,里面包含了标识首次请求,下拉刷新,上拉加载更多和各种请求反馈状态值的静态常量:

public class RequestApi {

    public static int RequestParmError_Code = -1; // 请求参数异常状态值
    public static int NotLoad_Code = 0; // 没有调用请求状态
    public static int NetWorkError_Code = 1;// 网络异常状态值
    public static int NoMoreData_Code = 2;// 没有更多数据状态值
    public static int LoadDataSuccess_Code = 3;// 初次加载数据成功状态值
    public static int LoadDataFail_Code = 4;// 初次加载数据失败状态值
    public static int RefreshDataSuccess_Code = 5;// 刷新数据成功状态值
    public static int LoadMoreSuccess_Code = 6;// 加载更多数据成功状态值

    public static int FirstLoadData = 8;// 第一次加载状态值
    public static int RefreshData = 9;// 刷新数据状态值
    public static int LoadMoreData = 10;// 加载更多状态值

}

viewmodel代码:

import android.arch.lifecycle.MutableLiveData
import android.arch.lifecycle.ViewModel
import android.content.Context
import android.databinding.ObservableInt
import android.util.Log
import android.view.View
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers

// 我这里是使用的封装好的retrofit2网络请求,你在使用时换成你自己的网络封装需要,然后有几次需要导的包你用不到,我给删了import路径了
class WallpaperListActViewModel:ViewModel(){
    private var TAG :String = "WallpaperListActivity"
    var loadStatusView = ObservableInt(View.VISIBLE)
    var category :String = ""
    var apiversion :String = "2.0"

    // 网络请求状态值的观察者变量,不同的请求反馈都会改变这个值,当这个观察者变量发生变化的时候它的观察者会得到通知
    var loadState:MutableLiveData<Int>  = MutableLiveData<Int>()

    companion object {
        var page_on :Int = 0
    }

init {
    loadState.value = RequestApi.NotLoad_Code
}

    fun loadData( requestCode:Int,context:Context){
        if (StringUtils.StringIsNull(category)){
            if (NetWorkUnits.isNetworkAvailable(context)){
                if (requestCode==RequestApi.FirstLoadData||requestCode==RequestApi.RefreshData){
                    page_on = 0
                }else{
                    page_on++
                }

                var server = MyAPP.Companion.initRetrofitInstance().create(IPServer::class.java)
                server.getWallpaperListData(category,page_on.toString(),apiversion)
                        .subscribeOn(Schedulers.newThread())
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe({result ->
                            if (result.code==0){
                                loadStatusView.set(View.GONE)

                                if (requestCode==RequestApi.FirstLoadData){
                                    StackSave.wallpaperBeanList.clear()
                                    StackSave.wallpaperBeanList.addAll(result.data.toMutableList())
                                    loadState.postValue(RequestApi.LoadDataSuccess_Code)
                                    loadStatusView.set(View.GONE)
                                }else if (requestCode==RequestApi.RefreshData){
                                    StackSave.wallpaperBeanList = result.data.toMutableList()
                                    loadState.postValue(RequestApi.RefreshDataSuccess_Code)
                                }else if (requestCode==RequestApi.LoadMoreData){
                                    StackSave.wallpaperBeanList.addAll(result.data.toMutableList())
                                    loadState.postValue(RequestApi.LoadMoreSuccess_Code)
                                }
                                Log.d(TAG,"请求成功----->"+result.data.toString())
                            }else if(result.code==1){
                                loadState.postValue(RequestApi.RequestParmError_Code)
                            }

                        },{error ->
                            loadStatusView.set(View.GONE)
                            Log.d(TAG,"请求失败--> error message:"+error.cause)
                            if (requestCode==RequestApi.FirstLoadData){
                                loadState.postValue(RequestApi.LoadDataFail_Code)
                            }else if (requestCode==RequestApi.RefreshData){
                            }else if (requestCode==RequestApi.LoadMoreData){
                            }

                        })
            }else{
                loadState.postValue(RequestApi.NetWorkError_Code)
            }
        }

    }


}

最后view层实现:

需要先在xml代码中加入一个layout标签,并指定对应的viewmodel文件路径:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>
        <variable
            name="wallpaperListActViewModel"
            type="你的包名.viewmodel.WallpaperListActViewModel" />
    </data>

     <--  在这里写你的布局代码,这里做了省略 -->
      


</layout>

activity中的代码:

class WallpaperListActivity: Activity() {

 override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

         initView()
         initData()

    }


        fun initData() {
        category = intent.getStringExtra("category")
        tv_wallpaper_title.text = category
        isVideo = intent.getBooleanExtra("isVideo",false)
        wallpaperListActViewModel?.category = category
        wallpaperListActViewModel?.loadData(RequestApi.FirstLoadData,this)

        // 对viewmodel中的进行加载状态值的变量进行观察监听变化,并当发生变化的时候判断并做对应的页面状态更新
        wallpaperListActViewModel?.loadState?.observe(this, Observer {state ->
            when(state){
                RequestApi.NetWorkError_Code ->{ Toast.makeText(this,"Request parameter exception", Toast.LENGTH_SHORT).show()}
                RequestApi.RequestParmError_Code ->{ Toast.makeText(this,"Net Work Error", Toast.LENGTH_SHORT).show()}
                RequestApi.LoadDataSuccess_Code ->{
                    adapter = WallpaperListAdapter(this,StackSave.wallpaperBeanList,isVideo,category)
                    swipe_target.adapter = adapter
                    wallpaperlist_load_status.setHide()
                }
                RequestApi.RefreshDataSuccess_Code ->{
                    adapter = WallpaperListAdapter(this,StackSave.wallpaperBeanList,isVideo,category)
                    swipe_target.adapter = adapter
                    walpaperlist_swipeToLoad?.isRefreshing = false
                }
                RequestApi.LoadMoreSuccess_Code ->{
                    lastItemsSize = StackSave.wallpaperBeanList.size
                    var itee: SimpleItemAnimator = swipe_target!!.itemAnimator as SimpleItemAnimator
                    itee.supportsChangeAnimations = false  //取消RecyclerView的动画效果
                    adapter!!.notifyItemRangeChanged(lastItemsSize, lastItemsSize)
                    walpaperlist_swipeToLoad?.isLoadingMore = false
                }
                RequestApi.NoMoreData_Code ->{  Toast.makeText(this,"No more data", Toast.LENGTH_SHORT).show() }
                RequestApi.LoadDataFail_Code ->{ wallpaperlist_load_status.setFailRefresh() }
            }
        })
    }




  @SuppressLint("NewApi")
    fun initView() {
       // 做databinding初始化
        initDataBinding()
        var layoutManager = GridLayoutManager(this,3)
        swipe_target.layoutManager = layoutManager as RecyclerView.LayoutManager?
       
        //添加过渡滑动
        walpaperlist_swipeToLoad.setRefreshCompleteDelayDuration(800)
        // 下拉刷新
        walpaperlist_swipeToLoad.setOnRefreshListener {
          wallpaperListActViewModel?.loadData(RequestApi.RefreshData,this)
        }
        // 下拉加载更多
        walpaperlist_swipeToLoad.setOnLoadMoreListener {
            wallpaperListActViewModel?.loadData(RequestApi.LoadMoreData,this)
        }
        wallpaperlist_load_status.setOnRefreshListener {  wallpaperListActViewModel?.loadData(RequestApi.FirstLoadData,this) }
        rl_back_btn.setOnClickListener {
            finish()
        }
        wallpaperlist_load_status.setLoading()
    }

    private fun initDataBinding() {
        dataBinding =  DataBindingUtil.setContentView(this,R.layout.activity_wallpaper_list)
        wallpaperListActViewModel = ViewModelProviders.of(this).get(WallpaperListActViewModel::class.java)
        dataBinding?.wallpaperListActViewModel = wallpaperListActViewModel
    }



}

好了,到此简单的mvvm的使用流程就完成了,欢迎大家看后进行留言评论交流探讨,谢谢!

发布了89 篇原创文章 · 获赞 231 · 访问量 62万+

猜你喜欢

转载自blog.csdn.net/wjj1996825/article/details/87784331