欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android MVC和MVP架构的详解

程序员文章站 2022-05-12 16:15:32
...
MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,
用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面
及用户交互的同时,不需要重新编写业务逻辑。其中
M层:处理数据,业务逻辑等;
V层:处理界面的显示结果;
C层:起到桥梁的作用,来控制V层和M层通信以此来达到分离视图、显示和业务逻辑层。


在Android中使用如下图:

Android MVC和MVP架构的详解

View 层:在开发中xml文件就是我们的View布局,一般情况下我们都会用xml来实现我们的布局,相对的节省性能的消耗。但是也有一些比较特殊、比较复杂的需求我们需要用到自定义view,其实自定义View也是属于View,这是比较少的情况,正常我们都会用xml来实现View的。

Controller层:控制层,其实Android已经默认给我们提供了Controller,就是Activity和Fragment,仔细一想就可以明白,用户在View层做出请求的操作,Activity和Fragment就会对用户做出的请求做出相应的处理,得到相应的结果之后,再呈现给用户。
其实对于Activity和Fragment人们有时会认为它是属于View层的。的确,在MVC的View层中的xml布局是不会改变的,而当用户在操作的时候我们的View总要做出相应的改变,而有些改变单单是xml是没办法做到的,所以在Activity和Fragment这个Controller层中多多少少都会有View层的东西。但是在Activity和Fragment中总归还是Controller层的代码占绝大多数,因此我们还是把它归类为Controller层。


Model层:Android中除了View和Controller,剩下的绝大多数来说都是Model层的东西了。其实Model一般不会被定义得很死,Model本身就数据和业务逻辑有关的,而不同的需求当然是有不同的数据和业务逻辑的,其中数据模型(javaBean)、数据的存取、网络的操作、以及一些耗时的任务等等。

项目结构:

Android MVC和MVP架构的详解

接下来Demo演示,数据模型类:

public class Person {
	private int per_id;
	private String username;
	private String sex;
	private int age;

	public Person(int per_id, String username, String sex,
			int age) {
		this.per_id = per_id;
		this.username = username;
		this.sex = sex;
		this.age = age;
	}

	public int getPer_id() {
		return per_id;
	}

	public void setPer_id(int per_id) {
		this.per_id = per_id;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}


	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "Person->[per_id=" + per_id + ", username=" + username
				+ ", sex=" + sex + ", age=" + age
				+ "]";
	}

}

获取数据侦听:

public interface GetDataListener {
	void onGetDataSuccess(Person person);

	void onGetDataError(String errmessage);
}

获取数据接口:

public interface GetData {
	void getShopsData(GetDataListener getDataListener);
}

获取数据:

public class GetDataImplement implements GetData {

	@Override
	public void getShopsData(GetDataListener getDataListener) {
		Person person = new Person(1, "layne", "male", 18);
		if(person!=null){
			getDataListener.onGetDataSuccess(person);
		}else{
			getDataListener.onGetDataError("请求失败");
		}
	}

}

控制层:

public class MainActivity extends ActionBarActivity implements GetDataListener,
		OnClickListener {
	private Button bt_request;
	private TextView tv_content;
	private GetData getData;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		InitView();

	}

	private void InitView() {
		bt_request = (Button) findViewById(R.id.bt_request);
		tv_content = (TextView) findViewById(R.id.tv_content);

		bt_request.setOnClickListener(this);

		getData = new GetDataImplement();
	}

	@Override
	public void onClick(View view) {
		switch (view.getId()) {
		case R.id.bt_request:
			getData.getShopsData(this);
			break;
		}

	}

	@Override
	public void onGetDataSuccess(Person person) {
		showData(person);

	}

	@Override
	public void onGetDataError(String errmessage) {
		Toast.makeText(this, errmessage, Toast.LENGTH_SHORT).show();

	}

	// 控制层将Model层里面的数据呈现到View层
	private void showData(Person person) {
		tv_content.setText(person.toString());
	}

}

视图层:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.itman.mvcdemo1.controller.MainActivity" >

    <Button
    android:id="@+id/bt_request"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="20dp"
    android:text="请求数据" />
    
   <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        android:orientation="horizontal" >

        <TextView
            android:id="@+id/tv_content"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="请求的内容" />

    </LinearLayout>
    
</LinearLayout>

运行结果:

Android MVC和MVP架构的详解     Android MVC和MVP架构的详解

总结:

MVC的优点:
很明显如果要求不高,我们平时的小项目就是一般的MVC,这个框架学习成本低,理解起来非常容易,对UI层与业务层进行分离,对Model层和数据方面做一下分层和封装,就是一个扩展性不错,挺清晰的MVC开发框架了。

但是缺点也是很明显的:
随着我们的业务壮大起来,需求越来越多,那么Activity和Fragment的代码就会越来越多,有的甚至夸张到一个activity就有几千行代码的,就会变得越来越臃肿,当我们维护和改变需求的时候是非常耗时间和精力的。这个就是MVC的缺点。



MVP架构

根据上文一开始MVC架构,项目随着需求不断增多,业务逻辑更加的复杂,我们的activity和fragment的代码也是越来越臃肿的。这时的activity和fragment理解和维护起来科室非常的费事费力,很痛苦的一件事,相信我们程序员都不太愿意去面对这样的情况的。这时MVP就应运而生,原先MVC中的Controller层activity或fragment将抽出控制层的代码,剩余的归类为View层,也就是说activity和fragment在MVP中是属于View层的,而被抽出的控制层代码成为了新的一员Presenter。
MVP的各个职责:
View层:
对应于Activity,负责View的绘制以及与用户交互,处理界面的显示结果
Model层:处理数据,业务逻辑等
Presenter层:负责完成View于Model间的交互

MVP其实就是减少了Activity和fragment的职责,减少了Activity和fragment的代码,将繁杂的逻辑代码交给了Presenter,相对应的好处就是耦合度更加的低,更方便单元测试了,同时借用两张图来说明变化(图片出处):

Android MVC和MVP架构的详解

转变为:

Android MVC和MVP架构的详解


MVC和MVP的区别(图片出处):根据图中我们可以知道在MVC中Model层是可以和View层交互的,但是在MVP中Model层和View层的交互是完全交给了Presenter的

Android MVC和MVP架构的详解

接下来我们根据上面的MVC的Demo,将之修改成MVP架构的Demo

项目结构

Android MVC和MVP架构的详解


数据模型:

public class Person {
	private int per_id;
	private String username;
	private String sex;
	private int age;

	public Person(int per_id, String username, String sex,
			int age) {
		this.per_id = per_id;
		this.username = username;
		this.sex = sex;
		this.age = age;
	}

	public int getPer_id() {
		return per_id;
	}

	public void setPer_id(int per_id) {
		this.per_id = per_id;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}


	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "Person->[per_id=" + per_id + ", username=" + username
				+ ", sex=" + sex + ", age=" + age
				+ "]";
	}

}

请求侦听:

public interface GetDataListener {
	void onGetDataSuccess(Person person);

	void onGetDataError(String errmessage);
}

Presenter接口:

public interface IGetDataPresenter {
	void getData(GetDataListener getDataListener);
	
	void clear();
}

Presenter:

public class GetDataPresenterCompl implements IGetDataPresenter {

	private IGetDataView getDataView;
	private Person person;

	public GetDataPresenterCompl(IGetDataView getDataView) {
		this.getDataView = getDataView;
	}

	@Override
	public void getData(GetDataListener getDataListener) {
		person = new Person(1, "layne", "male", 18);
		if (person != null) {
			getDataListener.onGetDataSuccess(person);
		} else {
			getDataListener.onGetDataError("请求失败");
		}
	}

	@Override
	public void clear() {
		getDataView.clearData();
	}

}

视图的接口:

public interface IGetDataView {
	
	void clearData();
}

Activity:

public class MainActivity extends ActionBarActivity implements IGetDataView,
		GetDataListener, OnClickListener {

	private Button bt_request, bt_clear;
	private TextView tv_content;
	
	private IGetDataPresenter getDataPresenter;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		InitView();
	}

	private void InitView() {
		bt_request = (Button) findViewById(R.id.bt_request);
		bt_clear = (Button) findViewById(R.id.bt_clear);
		tv_content = (TextView) findViewById(R.id.tv_content);

		bt_request.setOnClickListener(this);
		bt_clear.setOnClickListener(this);
		
		getDataPresenter = new GetDataPresenterCompl(this);
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.bt_request:
			getDataPresenter.getData(this);
			break;

		case R.id.bt_clear:
			getDataPresenter.clear();
			break;
		}

	}

	@Override
	public void onGetDataSuccess(Person person) {
		showData(person);

	}

	@Override
	public void onGetDataError(String errmessage) {
		Toast.makeText(this, errmessage, Toast.LENGTH_SHORT).show();

	}

	@Override
	public void clearData() {
		tv_content.setText("清空内容");

	}
	
	private void showData(Person person) {
		tv_content.setText(person.toString());
	}


}

最后是布局文件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.itman.mvpdemo.view.MainActivity" >

    <Button
        android:id="@+id/bt_request"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        android:layout_marginTop="5dp"
        android:text="请求数据" />

    <Button
        android:id="@+id/bt_clear"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        android:layout_marginTop="5dp"
        android:text="清除数据" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        android:orientation="horizontal" >

        <TextView
            android:id="@+id/tv_content"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="请求的内容" />
    </LinearLayout>

</LinearLayout>

运行结果:

Android MVC和MVP架构的详解   Android MVC和MVP架构的详解   Android MVC和MVP架构的详解

MVP的优点:
1.更加的降低了耦合度,使得Model层和View层的完全解耦
2.模块职责划分清楚,层次分明
3.Presenter一定程度下可以复用,一个Presenter可用于多个View,前提是View的改动不影响业务逻辑。
4.单元测试更加的方便


缺点:
1.层次分明的代价是额外的代码和类,这更加的增加了学习成本
2.如果Presenter过多地与特定的视图的联系过于紧密,一旦视图需要变更,那么Presenter也需要变更了。

相关标签: Android MVC MVP