Android MVC、MVP、MVVM模式思想的应用

一、前言

记得当时接触到的第一个架构就是MVC。由于经验不足,最开始一直不知道这个是做什么的,有什么用。直到后面慢慢的才懂得原来是一种开发模式,目的就是解藕,复用等。
去年的某一天,在推酷上读到一篇博文,第一次了解到MVP模式。从字里行间可以感受到作者对于此模式的崇拜,以及内心的欢喜。当时没有仔细的去写demo研究它,只是大概的看了下它跟MVC的区别。感觉还是很不错。现在终于有时间来仔细的去研究一下它。

二、何谓MVP

在讲MVP之前,先说下MVC中M\V\C三者各自代表的含义。
1,MVC:
M—Model:业务逻辑和实体对象,比如:UserBean(用户实体对象),里面可以有age,sex,height,weight等等属性。UserBiz(用来管理用户行为的业务逻辑对象),在这里它也是一个Model,可以通过它来操作用户的登录、退出,修改用户信息等行为。

V—View:视图层。这里的视图层由Activity,Fragment,及View等充当。

C—Controller:控制层。官方的说法是Controller对应于Activity,

MVC模式中M\V\C三者的关系如下图(感谢Hongyang的图片):

这里写图片描述

由此可见,这里就有了一个模糊的界限:Activity既充当View又充当Controller.

2.MVP
M—Model:业务逻辑与实体对象层。基本上与MVC中的Model一样,
V—View:视图层。我个人的理解这里其实也是跟MVC中的V一样,由Activity,Fragment,View等组成。
P—Presenter:处理层。由Presenter从Model仓库中提取数据,之后放到View中进行显示。
这里也借用一下Hongyang的图片:

这里写图片描述

这样一来,我们不难发现为什么大家都说MVP就是MVC的一个升级版了。因为MVP就是在控件层进行了巧妙的处理,从而达到真的解藕与复用。也许你还是不怎么理解,没事,稍后我会贴出事例代码。
下面就是MVC与MVP二者之间的区别(来自:Hongyang):

这里写图片描述

三、Demo

下面贴出自己应用MVP模式写的一个简单Demo.
1,工程结构:
这里写图片描述

2,View层:
如上图所示,在这里我们写定义一个View接口类(IView),再定义一个抽象类来实现此接口(AbsView)。最后由具体实现类来继承此抽象类(LoginView)。

IView:


/**
 * Created by sunny on 2016/3/9.
 * Annotion:视图层接口
 */
public interface IView {
    /**
     * 创建视图
     * @param inflater
     * @param viewGroup
     * @param savedInstance
     */
    void createView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstance);

    /**
     * 实例化控件
     */
    void initWidget();

    /**
     * 获取根布局
     * @return
     */
    View getRootView();


}

AbsView:

/**
 * Created by sunny on 2016/3/9.
 * Annotion:视图层实现类,
 */
public abstract class AbsView implements IView ,View.OnClickListener{
    private SparseArray<View> mBindViews = new SparseArray<>();
    public Context context;
    private View rootView;

    @Override
    public void createView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstance) {
        rootView = inflater.inflate(getLayoutId(), viewGroup, false);
        context = rootView.getContext();
    }

    @Override
    public void initWidget() {
        //TODO 在这里是一个空方法,由子类去实现
    }

    @Override
    public View getRootView() {
        return rootView;
    }

    /**
     * 把子控件用一个集合存起来
     *
     * @param viewId
     * @param <T>
     * @return
     */
    public <T extends View> T bindView(int viewId) {

        T t = (T) mBindViews.get(viewId);
        if (t == null) {
            t = (T) rootView.findViewById(viewId);
            mBindViews.put(viewId, t);
        }

        return t;
    }

  /**
     * 设置点击监听
     *
     * @param view
     */
    public void bindView(View view){
        if(view != null){
            view.setOnClickListener(this);
        }
    }


    public <T extends View> T getViewById(int viewId) {
        T view = (T) rootView.findViewById(viewId);
        return view;
    }

    /**
     * 获取布局文件id
     *
     * @return
     */
    public abstract int getLayoutId();


    @Override
    public void onClick(View v) {

//TODO 这里可以不用写,由子类去复写。
    }
}

LoginView:

/**
 * Created by sunny on 2016/3/9.
 * Annotion:登录界面
 */
public class LoginView extends AbsView {

    private EditText mEditTextAccount;
    private EditText mEditTextPassword;

    private Button mBtnLogin;
    @Override
    public int getLayoutId() {
        return R.layout.presenter_activity_login;
    }

    @Override
    public View getRootView() {
        return super.getRootView();
    }

    @Override
    public void initWidget() {
        mEditTextAccount = (EditText) getRootView().findViewById(R.id.presenter_account);
        mEditTextPassword = (EditText) getRootView().findViewById(R.id.presenter_password);
        mBtnLogin = (Button) getRootView().findViewById(R.id.presenter_login);

        bindView(mBtnLogin);
    }

    @Override
    public void onClick(View v) {
        super.onClick(v);
        switch (v.getId()){
            case R.id.presenter_login:
                String account = mEditTextAccount.getText().toString();
                String password = mEditTextPassword.getText().toString();
                if(TextUtils.isEmpty(account)){
                    Toast.makeText(context,mEditTextAccount.getHint().toString(),Toast.LENGTH_SHORT).show();
                    return;
                }

                if(TextUtils.isEmpty(password)){
                    Toast.makeText(context,mEditTextPassword.getHint().toString(),Toast.LENGTH_SHORT).show();
                    return;
                }

                mEditTextPassword.setText("");
                mEditTextAccount.setText("");
                Toast.makeText(context,"登录成功",Toast.LENGTH_SHORT).show();
                break;
        }

    }
}

3:Presenter处理层:

ActivityPresenter:

**
 * Created by sunny on 2016/3/9.
 * Annotion:Presenter的实现基类
 */
public abstract class ActivityPresenter<T extends IView> extends Activity {

    private T mView;
    private Context context;

    /**
     * 由子类去实现它,通过newInstance来获取实例化对象
     * @return
     */
    public abstract Class<T> getResenterClass();

    public ActivityPresenter(){
        try {
            mView = getResenterClass().newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        context = this;
        if(mView != null){
            mView.createView(getLayoutInflater(),null,savedInstanceState);
        }
        setContentView(mView.getRootView());
        //初始化布局子控件
        mView.initWidget();
    }

    @Override
    protected void onStart() {
        super.onStart();
    }

    @Override
    protected void onResume() {
        super.onResume();
    }

    @Override
    protected void onStop() {
        super.onStop();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }
}

BaseActivity:

这个就跟我们平时写的BaseActivity差不多,只是这里它是一个抽象类,可以把一些通用的模块抽出成抽象方法,由子类去实现。


/**
 * Created by sunny on 2016/3/9.
 * Annotion:Activity基类(注意为抽象类)
 */
public abstract class BaseActivity<T extends IView> extends ActivityPresenter<T> {
}

LoginAtyPresenter:

这里就像我们平时的Activity了,得在AndroidManifist.xml中进行注册。


/**
 * Created by sunny on 2016/3/9.
 * Annotion:登录Presenter
 */
public class LoginAtyPresenter extends BaseActivity<LoginView> {

    public static void startLoginAtyPresenter(Context context){
        Intent targetIntent = new Intent(context,LoginAtyPresenter.class);
        context.startActivity(targetIntent);
    }
    @Override
    public Class getResenterClass() {
        return LoginView.class;
    }
}
 <!--Android MVP模式-->
        <activity android:name="sunnydemo2.mvp.presenter.LoginAtyPresenter"/>

运行结果如下:
这里写图片描述

到这里就暂时告一段落了。这纯粹只是简单的运用。在实际项目中,像空白页面,网络请求都可以抽象方法加进去,在具体的子类View中去实现就好了。

4、MVVM模式

MVVM模式,即数据绑定模式(Data Binder)是google官方在2015开发者大会上提出来的。
M—-Model:业务逻辑对象。
V—-View:视图对象。
VM—-:View-Model:把数据与视图绑定起来。

Data Binder需要Android Studio支持,在Android Studio2.0版本以前得自行在build.gradle 里面加上databinding的依赖。而AndroidStudio2.0以后由于自身已经集成了,就不再需要手动依赖。只需如下设置一下即可。

 dataBinding {
        enabled true
    }

Data Binding是一个支持库,可以兼容Android2.1以上的所有版本。
另外,Gradle版本需要1.5.0-alpha1及以上版本。

接下来就根据google官方文档来讲讲Data Binding的基本流程及原理(PS:其实嘛,就是简单翻译,只要能明白其大致流程就ok了。):

系统会根据DataBinding 的布局文件以既定的规则(以短下划线为分隔线,每个词的首字母大写,写Binding为后缀结束。eg:activity_login.xml生成绑定类后名字为:ActivityLoginBinding)生成相对应的类,并放入相应的包(eg:原module包名为:com.sunny.test,则放入:com.sunny.test.databinding包下)下。

databinding的xml布局文件跟我们之前的layout有区别。
根据下面的简单例子作说明:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
   <data>
       <variable name="user" type="com.example.User"/>
   </data>
   <LinearLayout
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.firstName}"/>
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.lastName}"/>
   </LinearLayout>
</layout>

它是以开头,紧接着,再下面就是我们平时的布局文件。
在这里,是核心。它里面可以接收各种参数,而这些都由来实现,如上例所示:type表示接收User类,name表示实体类User的对象名.
这还可以用另外一种形式表达:

<data>
<import type="com.example.User"/>
<variable name="user" type="User"/>
</data>

这个很容易理解:导入User类,实现化User对象user.同时系统会根据user生成setter,getter方法:setUser(User userModel),getUser();

接下来就是在布局中把数据取出来与view进行绑定。
还是看上面例子:

<LinearLayout
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.firstName}"/>
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.lastName}"/>
   </LinearLayout>

这是在xml中取出数据后,与view进行绑定,那么这数据源从哪里set进来呢?
一开始我们说到,它会根据databinding的布局文件生成相应的类。故数据是从这生成的类set进来的。

public class BasicActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ActivityBasicBinding binding = DataBindingUtil.setContentView(
                this, R.layout.activity_basic);
        User user = new User("Yanguo", "Li", 27);
        binding.setUser(user);
    }
}

目前MVVM还不适合用于正式的大项目,期待google 在AndroidN上能对dataBinding发出一个正式的稳定版本。
官网讲的很详细,各位可以去学习下:Data Binding

### 回答1: MVCMVPMVVM 是三种设计模式,用于在 Android 应用程序中组织代码。 MVC(模型-视图-控制器):模型存储应用程序数据,视图显示数据,控制器处理用户交互。 MVP(模型-视图-presenter):与 MVC 类似,但 presenter 更加紧密地与视图绑定,负责更新视图。 MVVM(模型-视图-视图模型):与 MVP 类似,但视图模型与视图绑定,负责将数据转换为视图可用的形式。 三者的差异在于MVC会产生视图和模型之间的耦合,MVPMVVM是将视图和模型之间的耦合分离,更加灵活。 ### 回答2: Android开发中,MVCMVPMVVM都是常见的架构模式,用来组织Android应用的代码结构,让代码更加规范、易于维护。 MVC(Model-View-Controller)是最早的一种架构模式,它将应用分为三个模块:模型(Model)、视图(View)和控制器(Controller)。其中模型负责数据的存储和操作,视图负责显示界面,控制器则负责对用户输入进行响应,协调模型和视图之间的关系。MVC模式的优点是结构清晰,各个模块职责分明,易于实现代码复用,因此广泛应用。但是MVC模式也有一些缺点,比如控制器中很难进行单元测试,代码复杂度较高,难以维护大型项目等问题。 MVP(Model-View-Presenter)是一种基于MVC模式的改进,它将模型和视图分离,通过在中间加上Presenter来连接两者。Presenter接受用户的输入,并根据视图的状态更新数据模型,然后更新视图显示。MVP模式的优点是易于单元测试,将业务逻辑和界面分离,代码复杂度较低,易于维护。但是对于大型项目,Presenter层也会变得庞大且复杂。 MVVM(Model-View-ViewModel)是一种结合数据绑定和命令模式的前端设计模式,它将模型、视图和ViewModel分开,通过数据绑定将视图和ViewModel联系起来。ViewModel封装了视图的状态和行为,当ViewModel被修改时,视图会自动更新。MVVM模式的优点是将视图和ViewModel解耦,通过数据绑定自动更新视图,提高了代码的可重用性。但MVVM模式需要使用大量的数据绑定,可能导致系统卡顿,同时实现较为复杂。 总的来说,MVCMVPMVVM这三种模式都有各自的适用场景。在小型项目中,可以使用MVC模式;在中型项目中,可以使用MVP模式;在大型项目中,可以使用MVVM模式。选择合适的架构模式能够让代码更易于维护,提高开发效率。 ### 回答3: Android是一种以Java为基础的开源操作系统,广泛应用于移动设备中。在开发Android应用程序时,常用的三种架构模式MVCMVPMVVMMVC是一种典型的应用程序架构模式,其中M代表模型,V代表视图,C代表控制器。在Android中,MVC通常用规定ViewController或Activity来实现。 MVP是Model-View-Presenter的缩写,其中M代表模型,V代表视图,P代表演示者。MVP将视图项分离,并引入中间者Presenter,以实现界面和业务逻辑分离的目的。在Android中,MVP通常实现在Activity或Fragment上。 MVVM是Model-View-ViewModel的缩写,其中M代表模型,V代表视图,VM代表视图模型。ViewModel担任中间件角色,处理视图中的数据,并使控制逻辑与视图分离开。在Android中,MVVM通常实现了Data Binding。 总的来说,三种架构模式都旨在将应用程序分离成各个组成部分,每个部分具有各自分离的职责,在开发Android应用程序时选择合适的架构模式,能够提高开发效率、提高代码质量、降低维护成本、提高整个应用程序的可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值