MVC、MVP、MVVM彻底理解

背景

随着Android的成熟Android的应用架构越来越多受到重视,因为程序的维护和扩展远远比开发成本要高很多,选用良好的的设计架构能很好地维护和扩展程序

1.MVC 模式

(1)Model 我们针对业务模型,建立数据结构和相关的类

(2)View 一般可以表达为xml文件的布局

(3)Controller 在Activity的逻辑处理可以认为是控制层

优缺点
MVC 模式的一个优点就是使用简单,我们最简单的一个入门demo就是一个mvc模式,但是存在的缺点就是view和model层存在耦合,然后就是Activity的逻辑结构太复杂,它既要承当页面的展示又要处理逻辑功能,当页面复杂之后逻辑将变得难以维护。

2.MVP模式

Model 主要提供提供数据的存储功能,presenter需要通过model层来存储数据,获取数据
View 负责处理用户事件和视图部分的展示,在Android可能是Activity,Fragment
Presenter:作为View和Model之间的桥梁,它从model层检索数据后返回view,使得view和model之间没有耦合
在MVP中 Presenter 完全将model和View进行了分离,主要的程序逻辑在Presenter里面实现,P与V没有直接关联,而是通过接口进行交互,从而使在变更view时候可以保持P不变。

2.1 应用MVP模式

自己随意定义的实体类
public class IpData {
    private String country;
    private String city;

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }
}



public class Model {
    private int code;
    private IpData data;

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public IpData getData() {
        return data;
    }

    public void setData(IpData data) {
        this.data = data;
    }
}
抽取出一部分网络请求的定义和实现
public interface LoadTaskCallBack<T> {
    void onSuccess(T t);

    void onStart();

    void onFailed();

    void onFinish();

}



public interface NetTask<T> {
    void execute(T data,LoadTaskCallBack callback);
}

public class IpInfoTask implements NetTask<String> {
    private static IpInfoTask mInstance = null;
    private static final String HOST = "http:www.baidu.com";
    private LoadTaskCallBack loadTaskCallBack;
    private IpInfoTask() {
    }
    public static IpInfoTask getmInstance() {
        if (mInstance == null) {
            mInstance = new IpInfoTask();
        }
        return mInstance;
    }
    @Override
    public void execute(String data, final LoadTaskCallBack callback) {

        RequestParams requestParams = new RequestParams();
        requestParams.addFormDataPart("ip", data);
        HttpRequest.post(HOST, requestParams, new BaseHttpRequestCallback<IpData>() {
            @Override
            public void onStart() {
                super.onStart();
                callback.onStart();
            }

            @Override
            protected void onSuccess(IpData ipData) {
                super.onSuccess(ipData);
                callback.onSuccess(ipData);
            }

            @Override
            public void onFailure(int errorCode, String msg) {
                super.onFailure(errorCode, msg);
                callback.onFailed();
            }

            @Override
            public void onFinish() {
                super.onFinish();
                callback.onFinish();
            }
        });
    }
}
定义p层与v层的接口
public interface IpInfoContract {

    interface Presenter {
        void getIpInfo(String ip);
    }

    interface View extends BaseView<Presenter> {
        void setIpInfp(IpData ipInfp);

        void showLoader();

        void hideLoading();

        void showError();

        boolean isActive();
    }
}

让P层去实现接口实现各种逻辑操作 然后调用v层的接口

public class IpInfoPresenter implements IpInfoContract.Presenter, LoadTaskCallBack {
    private NetTask netTask;
    private IpInfoContract.View addTaskView;

    public IpInfoPresenter(NetTask netTask, IpInfoContract.View addTaskView) {
        this.netTask = netTask;
        this.addTaskView = addTaskView;
    }

    @Override
    public void getIpInfo(String ip) {
        netTask.execute(ip, this);
    }


    @Override
    public void onSuccess(Object o) {
        addTaskView.setIpInfp((IpData) o);
    }

    @Override
    public void onStart() {
        addTaskView.showLoader();

    }

    @Override
    public void onFailed() {
        addTaskView.showError();
    }

    @Override
    public void onFinish() {
        addTaskView.hideLoading();
    }
}


我们可以看到 在view层只是实现了view接口然后实现了各种接口的ui上的实现细节,需要实现什么方法就调用P层的什么方法,p层处理完逻辑之后就会通过传入的view接口来实现ui上的改变,实现逻辑的分离。
public class MainActivity extends AppCompatActivity implements IpInfoContract.View {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        IpInfoTask ipInfoTask = IpInfoTask.getmInstance();
        IpInfoPresenter ipInfoPresenter = new IpInfoPresenter(ipInfoTask, this);
        ipInfoPresenter.getIpInfo("地址");
    }
Override
    public void setIpInfp(IpData ipInfp) {
        //做ui上的操作
    }
    @Override
    public void showLoader() {
        //做ui上的操作
    }
    @Override
    public void hideLoading() {
        //做ui上的操作
    }
    @Override
    public void showError() {
        //做ui上的操作
    }
    @Override
    public boolean isActive() {
        return false;
    }
    @Override
    public void setPresenter(IpInfoContract.Presenter presenter) {
    }
}

3.MVVM 模式

学习MVVM之前需要理解DataBind这个东西
我们先定义一个随意的实体类
package com.example.weihuada.mvvm;

public class Swordsman {
    private String name;
    private String level;


    public Swordsman(String name, String level) {

        this.name = name;
        this.level = level;

    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getLevel() {
        return level;
    }

    public void setLevel(String level) {
        this.level = level;
    }
}

定义一个布局文件
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>

        <variable
            name="sowrdsman"
            type="com.example.weihuada.mvvm.Swordsman"></variable>
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{sowrdsman.name}" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{sowrdsman.level}" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/bt_next"
            />


    </LinearLayout>

</layout>
通过Activity将布局文件和实体类联系起来
import com.example.weihuada.mvvm.databinding.ActivityMain2Binding;

public class Main2Activity extends AppCompatActivity {
    private ActivityMain2Binding mBind;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mBind = DataBindingUtil.setContentView(this, R.layout.activity_main2);
        Swordsman swordsman = new Swordsman("张无忌", "s");
        mBind.setSowrdsman(swordsman);
        mBind.btNext.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(Main2Activity.this, "点击了", Toast.LENGTH_SHORT).show();
            }
        });
    }
}

上面的代码就是dataBind基本用法,也有其他的用法
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <data>

        <import type="java.util.ArrayList"></import>

        <import type="java.util.Map"></import>

        <variable
            name="list"
            type="ArrayList"></variable>

        <variable
            name="map"
            type="Map"></variable>

        <variable
            name="arrays"
            type="String[]"></variable>


    </data>


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{list.get(1)}" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{map.get(`map`)}" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{arrays[1]}" />
    </LinearLayout>

</layout>

一些运算符
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{`age`+String.valueOf(age)}"></TextView>


        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="三目运算符"
            android:visibility="@{man?View.VISIBLE:View.GONE}" />
双向绑定数据
第一种绑定方法 使用BaseObservable
public class ObSwordsman extends BaseObservable {
    private String name;
    private String level;


    public ObSwordsman(String name, String level) {
        this.name = name;
        this.level = level;
    }

    @Bindable
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
        notifyPropertyChanged(BR.name);
    }

    @Bindable
    public String getLevel() {
        return level;
    }

    public void setLevel(String level) {
        this.level = level;
        notifyPropertyChanged(BR.name);

    }
}

第二种绑定的方法 使用ObservableField
package com.example.weihuada.mvvm;

import android.databinding.BaseObservable;
import android.databinding.Bindable;
import android.databinding.ObservableField;

public class ObFSwordsman {

    public ObservableField<String> name = new ObservableField<>();
    public ObservableField<String> level = new ObservableField<>();


    ObFSwordsman(String name,String level){
        this.name.set(name);
        this.level.set(level);
    }

    public ObservableField<String> getName() {
        return name;
    }

    public void setName(ObservableField<String> name) {
        this.name = name;
    }

    public ObservableField<String> getLevel() {
        return level;
    }

    public void setLevel(ObservableField<String> level) {
        this.level = level;
    }
}

前面讲到model实体改变如何影响到ui反过来 如果ui发生改变如何影响model呢?
通过EditText的@={sowrdsman.name}方法实现数据的绑定
<EditText
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" 
            android:text="@={sowrdsman.name}"
            />
这样就实现了双向绑定了
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值