Android中MVC、MVP、MVVM模式<一>
2016-11-24 15:41
337 查看
完整代码: https://github.com/fenggit/Lesson01-mvc-mvp-mvvm
效果图:
输入用户名和密码
校验用户是否输入用户名和密码
请求服务器
具体实现:
代码结构
具有实现
常规实现的问题
Activity类包含内容:网络请求+业务相关+界面相关
导致Activity类的庞大的,耦合度高,不利于扩展
剥离Activity中的网络请求模块到Model中,减轻Activity类的负担,这样Model层需要变更不需要变更Activity类
具有实现
将常规实现
添加
而
MVC实现的问题
Activity类包含内容:业务相关+界面相关
总体来说减轻了Activity的职责,但是业务和界面还是在Activity模块中;
解决方式:
如果将Activity中的业务拆分–>MVP
如果将Activity中的界面控件拆分–>MVVM
Presenter链接View和Model,使用接口进行隔离Activity业务和View.
与MVC明显的特点就是View和Model不可以直接通信
其中:
具有实现
其中
添加Presenter层
添加
更改
MVP实现的问题
主要就是分解Activity职责,原本Activity包含:网络请求+业务相关+界面相关等三个模块,现在完全解耦合;网络请求数据由model层处理,业务相关由presenter处理,而界面View层由Activity处理UI和layout中xml布局;
完整代码: https://github.com/fenggit/Lesson01-mvc-mvp-mvvm
效果图:
一. Android中的MVC模式
1. 对应关系
MVC | M | C | V |
---|---|---|---|
全称 | Model | Controller | View |
含义 | 模型 | 控制层 | 界面 |
对应Android的模块 | 网络请求,数据库 | Activity、Fragment | 自定义View、layout布局(xml文件) |
2. 关系图
3. 登录模块常见写法
登录模块功能:输入用户名和密码
校验用户是否输入用户名和密码
请求服务器
具体实现:
代码结构
具有实现
LoginActivity代码
public class LoginActivity extends AppCompatActivity { private EditText mUserView; private EditText mPasswordView; private Button mLoginView; private ProgressDialog mProgressDialog; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); mUserView = (EditText) findViewById(R.id.et_user); mPasswordView = (EditText) findViewById(R.id.et_password); mLoginView = (Button) findViewById(R.id.btn_login); mLoginView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { login(); } }); } /** * 登录 */ public void login() { String user = mUserView.getText().toString(); String pwd = mPasswordView.getText().toString(); if (checkInput(user, pwd)) { mProgressDialog = ProgressDialog.show(this, null, "正在登录"); // 模拟请求数据 new Thread(new Runnable() { @Override public void run() { // 假设请求数据1秒 SystemClock.sleep(1000); // 更新UI runOnUiThread(new Runnable() { @Override public void run() { mProgressDialog.dismiss(); Toast.makeText(getBaseContext(), "登录成功", Toast.LENGTH_SHORT).show(); } }); } }).start(); } } /** * 检查输入是否合法 * * @param user * @param pwd * @return */ public boolean checkInput(String user, String pwd) { if (TextUtils.isEmpty(user)) { Toast.makeText(this, "请输入用户名", Toast.LENGTH_SHORT).show(); return false; } if (TextUtils.isEmpty(pwd)) { Toast.makeText(this, "请输入密码", Toast.LENGTH_SHORT).show(); return false; } return true; } }
布局代码activity_login.xml
<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:gravity="center_horizontal" android:orientation="vertical" android:padding="16dp" tools:context="com.fenggit.lesson01.login.LoginActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="用户名:" /> <EditText android:id="@+id/et_user" android:layout_width="match_parent" android:layout_height="48dp" android:hint="请输入用户名" /> </LinearLayout> <LinearLayout android:id="@+id/email_login_form" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="密码:" /> <EditText android:id="@+id/et_password" android:layout_width="match_parent" android:layout_height="48dp" android:hint="请输入密码" android:inputType="textPassword" /> </LinearLayout> <Button android:id="@+id/btn_login" style="?android:textAppearanceSmall" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:text="登录" android:textAllCaps="false" android:textStyle="bold" /> </LinearLayout>
常规实现的问题
Activity类包含内容:网络请求+业务相关+界面相关
导致Activity类的庞大的,耦合度高,不利于扩展
4. 通过MVC模式改造登录模块
代码结构剥离Activity中的网络请求模块到Model中,减轻Activity类的负担,这样Model层需要变更不需要变更Activity类
具有实现
将常规实现
login()的实现更改为:
/** * 登录 */ public void login() { String user = mUserView.getText().toString(); String pwd = mPasswordView.getText().toString(); if (checkInput(user, pwd)) { mProgressDialog = ProgressDialog.show(this, null, "正在登录"); // 使用model层 mLoginRequest.request(user, pwd, new LoginRequest.ResultListener() { @Override public void onSuccess() { // 更新UI runOnUiThread(new Runnable() { @Override public void run() { mProgressDialog.dismiss(); Toast.makeText(getBaseContext(), "登录成功", Toast.LENGTH_SHORT).show(); } }); } @Override public void onFail() { } }); } }
添加
model模块,LoginRequest 请求数据类
public class LoginRequest { /** * 模拟请求网络数据 * * @param user * @param pwd * @param resultListener * @return */ public boolean request(final String user, final String pwd, final ResultListener resultListener) { // 模拟请求数据 new Thread(new Runnable() { @Override public void run() { // 假设请求数据1秒 SystemClock.sleep(1000); Log.e("LoginRequest", "请求数据:" + user + "," + pwd); if (resultListener != null) { // 密码和用户是123 则登录成功 if("123".equals(user)&&"123".equals(pwd)){ resultListener.onSuccess(); }else{ resultListener.onFail(); } } } }).start(); return true; } public interface ResultListener { public void onSuccess(); public void onFail(); } }
而
view模块可以自定义view,而Android中layout中xml就是view模块
MVC实现的问题
Activity类包含内容:业务相关+界面相关
总体来说减轻了Activity的职责,但是业务和界面还是在Activity模块中;
解决方式:
如果将Activity中的业务拆分–>MVP
如果将Activity中的界面控件拆分–>MVVM
二. Android中的MVP模式
1. 对应关系
MVP | M | V | P |
---|---|---|---|
全称 | Model | View | Presenter |
含义 | 模型 | 界面 | 连接View和Model的桥梁 |
对应Android模块 | 网络请求,数据库 | 自定义View、layout布局(xml文件) | 业务逻辑 |
2. 关系图
与MVC明显的特点就是View和Model不可以直接通信
3. 通过MVP模式改造登录模块
代码结构其中:
LoginRequest为Model层,主要是网络请求相关;
LoginPresenter为Presenter层,主要是登录模块业务层
ILoginView为View层,主要是关联业务和UI操作,传递接口而不传递Activity和Fragment主要是为了通用性,Presenter业务操作完需要更新UI。
LoginActivity为纯界面相关操作,实现
ILoginView接口
具有实现
其中
LoginRequest和上面一样,Model不变;
添加Presenter层
LoginPresenter业务层
public class LoginPresenter { private Context context; private LoginRequest mLoginRequest; // 这里传入接口,主要为了通用性,界面可能是Activity和Fragment private ILoginView mView; public LoginPresenter(Context context, ILoginView view) { this.context = context; this.mView = view; this.mLoginRequest = new LoginRequest(); } /** * 登录 * * @param user * @param pwd */ public void login(String user, String pwd) { mLoginRequest.request(user, pwd, new LoginRequest.ResultListener() { @Override public void onSuccess() { // 登录成功,新UI mView.success(); } @Override public void onFail() { // 登录失败,新UI mView.fail(); } }); } /** * 检查输入是否合法 * * @param user * @param pwd * @return */ public boolean checkInput(String user, String pwd) { if (TextUtils.isEmpty(user)) { Toast.makeText(context, "请输入用户名", Toast.LENGTH_SHORT).show(); return false; } if (TextUtils.isEmpty(pwd)) { Toast.makeText(context, "请输入密码", Toast.LENGTH_SHORT).show(); return false; } return true; } }
添加
View层接口ILoginView
public interface ILoginView { /** * 登录成功 */ void success(); /** * 登录失败 */ void fail(); }
更改
LoginActivity代码,此类只保留UI相关操作
public class LoginActivity extends AppCompatActivity implements ILoginView { private EditText mUserView; private EditText mPasswordView; private Button mLoginView; private ProgressDialog mProgressDialog; private LoginPresenter mLoginPresenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); mUserView = (EditText) findViewById(R.id.et_user); mPasswordView = (EditText) findViewById(R.id.et_password); mLoginView = (Button) findViewById(R.id.btn_login); // 第一个是Context对象,第二个是ILoginView mLoginPresenter = new LoginPresenter(this, this); mLoginView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { login(); } }); } /** * 登录 */ public void login() { String user = mUserView.getText().toString(); String pwd = mPasswordView.getText().toString(); if (mLoginPresenter.checkInput(user, pwd)) { mProgressDialog = ProgressDialog.show(this, null, "正在登录"); mLoginPresenter.login(user, pwd); } } public void success() { runOnUiThread(new Runnable() { @Override public void run() { mProgressDialog.dismiss(); Toast.makeText(getBaseContext(), "登录成功", Toast.LENGTH_SHORT).show(); } }); } public void fail() { runOnUiThread(new Runnable() { @Override public void run() { mProgressDialog.dismiss(); Toast.makeText(getBaseContext(), "登录失败", Toast.LENGTH_SHORT).show(); } }); } }
MVP实现的问题
主要就是分解Activity职责,原本Activity包含:网络请求+业务相关+界面相关等三个模块,现在完全解耦合;网络请求数据由model层处理,业务相关由presenter处理,而界面View层由Activity处理UI和layout中xml布局;
三. Android中的MVVM模式
未完待续,见下一篇博客完整代码: https://github.com/fenggit/Lesson01-mvc-mvp-mvvm
相关文章推荐
- MVVM模式下如何使用ReactiveCocoa响应链式编程<一>
- Android中常用的设计模式<一>
- Java/Android 设计模式<一> 单例模式+建造者模式
- 浅学设计模式之模板<Template>方法模式及在android中的应用
- 理解不變模式-Immutable Pattern<一>
- Android开发工具——ADB(Android Debug Bridge) <一>概览
- 浅学设计模式之观察者<Observer>模式及在android中的应用 .
- android联系人app<一>
- Nop-Fluent+AutoFAC模式在ASP.NET MVC中的应用场景<四>
- 【Android开发学习45】使用google语音识别引擎(Google Speech API)<一>
- android 四大组件之--------------Service <一>
- (转)Android开发工具——ADB(Android Debug Bridge) <一>概览
- 【Android开发学习45】使用google语音识别引擎(Google Speech API)<一>
- MVC 只是一个思想,不是模式!! (3)关于回显<特别重要>
- android <初级篇> 界面布局<一> ——菜鸟的学习之路
- Android <Android应用开发实战> 资源类型<一>
- 设计模式入门--设计模式学习笔记<一>
- android基础学习<一>--->五大布局对象Framelayout,Linearlayout,Relativelayout,Tablelayout,AbsoluteLayout
- 浅学设计模式之观察者<Observer>模式及在android中的应用
- Android 新API 之 MediaCodec使用笔记 <一>