Android架构:MVP模式实例
2016-03-04 17:33
721 查看
现在的安卓开发已经很成熟,不像几年前大部分人还处于技术摸索阶段,当技术问题不再是安卓开发的难题时,更多人开始关注架构设计,代码质量,更想易于测试,维护方便,逻辑清晰。大家试图让所有的代码都高度解耦,各层分离,从而达到目的。MVP的架构模式,就这样应运而生。这里我希望以最简单的例子,让大家快速入门MVP模式。
对比MVC,MVP模式的特点是V层和M层不可互相接触,需要通过主导器Presenter进行关联,P层进行所有的逻辑处理,V层仅仅负责视图展示,M层负责获取数据。
下面是MVC和MVP对比图:
图片出处
既然要解耦,必然是面向接口的编程,就按照写代码的顺序从Model开始看:
LoginModel.java
对于Model层,没有什么多余的方法,就是完成登录,把结果返回给Presenter。这里我又写了一个接口OnLoginListener,为了给Presenter回调,让View和Model分离,当然,如果我们的框架中使用了otto之类的东东,那就不需要这个接口。接着看上面接口的实现:
LoginModelImpl.java
这里使用Volley网络框架,假设登录成功后,返回的json数据是这个类型:
那么我的实体Bean可以这么设计:
上述代码就完成了Model层,因为Presenter是M和V的联络人,所以,我们再把View层写了,同样,需要先写接口,这个接口里面我们写什么呢,就是在页面上,会发生的所有事,比如,获取用户名密码,点击登录后有进度条提示,登录反馈后取消提示等。
我们能想到的都写进来了,接着我们写这个接口的实现类,就是个Activity。
看上面的代码,很简洁,没有任何逻辑代码,这就是我们想要的效果,接下来就开始写Presenter层了,逻辑代码也是写到这一层。
实现:
在LoginPresenterImpl 类中,我们实例了LoginView 和LoginModel 。登录的逻辑就是先判断用户名和密码是否为空,不为空再调用Model里的登录方法,进行登录。因为Model层把登录反馈传给OnLoginListener 这个回调接口,所有我们在这里实现这个接口,就能获取登录后的反馈。OnSuccess和OnError分别是登录成功和失败后,通知View层应该显示什么。
这样,我们用MVP写出来的登录就完成了,总体思想就是,Model层获取的数据交给Presenter处理,Presenter进行处理的过程中,会通知页面View层进行相应变化,View层本身不进行逻辑处理,MVP架构及时各有分工。
整体工程里面还有个别不涉及本文内容的我没有详述,源码地址,点击这里下载
认识MVP
MVP就是Model,View,Presenter的缩写。对比MVC,MVP模式的特点是V层和M层不可互相接触,需要通过主导器Presenter进行关联,P层进行所有的逻辑处理,V层仅仅负责视图展示,M层负责获取数据。
下面是MVC和MVP对比图:
图片出处
实例
依然是最简单的登录页面,我通过一个登录业务,来详述MVP在项目中的使用,文后会附上代码地址。既然要解耦,必然是面向接口的编程,就按照写代码的顺序从Model开始看:
LoginModel.java
/** * Created by yuankundong on 2016/03/03. */ public interface LoginModel { void toLogin(String username, String password, OnLoginListener onLoginListener); }
对于Model层,没有什么多余的方法,就是完成登录,把结果返回给Presenter。这里我又写了一个接口OnLoginListener,为了给Presenter回调,让View和Model分离,当然,如果我们的框架中使用了otto之类的东东,那就不需要这个接口。接着看上面接口的实现:
LoginModelImpl.java
/** * Created by yuankundong on 2016/03/03. */ public class LoginModelImpl implements LoginModel{ String url = "http://xxxxx"; public final static int TIME_OUT_CODE = 99; public final static String TIME_OUT_MSG = "网络连接不可用,请稍后重试"; @Override public void toLogin(final String username, final String password, final OnLoginListener onLoginListener) { StringRequest stringRequest = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() { @Override public void onResponse(String response) { Type type = new TypeToken<UserBean>() { }.getType(); Gson gson = new Gson(); UserBean userBean = gson.fromJson(response, type); if (userBean.isSuccess()) { onLoginListener.OnSuccess(userBean); } else { onLoginListener.OnError(userBean.getCode(), userBean.getMsg()); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { onLoginListener.OnError(TIME_OUT_CODE, TIME_OUT_MSG); } }) { protected Map<String, String> getParams() throws AuthFailureError { Map<String, String> map = new HashMap<>(); map.put("phone", username); map.put("password", MD5Utils.stringToMD5(password)); return map; } }; BaseApplication.requestQueue.add(stringRequest); } }
这里使用Volley网络框架,假设登录成功后,返回的json数据是这个类型:
{ "code": 0, "msg": "登录成功" }
那么我的实体Bean可以这么设计:
/** * Created by yuankundong on 2016/03/03. */ public class UserBean { private int code; // 返回码,0为成功 private String msg; // 返回信息 public UserBean(int code, String msg) { this.code = code; this.msg = msg; } public boolean isSuccess() { return code == 0; } public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
上述代码就完成了Model层,因为Presenter是M和V的联络人,所以,我们再把View层写了,同样,需要先写接口,这个接口里面我们写什么呢,就是在页面上,会发生的所有事,比如,获取用户名密码,点击登录后有进度条提示,登录反馈后取消提示等。
/** * Created by yuankundong on 2016/03/03. */ public interface LoginView { //取得用户名 String getUsername(); //取得密码 String getPassword(); //登录成功后 void loginSuccess(); //登录失败后 void loginError(String msg); //展示进度条 void showProgress(); //隐藏进度条 void hideProgress(); //当需要弹出提示信息时 void showMessage(String msg); }
我们能想到的都写进来了,接着我们写这个接口的实现类,就是个Activity。
/** * Created by yuankundong on 2016/03/03. */ public class LoginActivity extends AppCompatActivity implements LoginView{ TextView username; TextView password; Button login; ProgressDialog dialog; LoginPresenter presenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); presenter = new LoginPresenterImpl(this); username = (TextView) findViewById(R.id.tv_username); password = (TextView) findViewById(R.id.tv_password); login = (Button) findViewById(R.id.btn_login); login.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { presenter.actionLogin(); } }); } @Override public String getUsername() { return username.getText().toString(); } @Override public String getPassword() { return password.getText().toString(); } @Override public void loginSuccess() { Toast.makeText(this, "登录成功", Toast.LENGTH_SHORT).show(); } @Override public void loginError(String msg) { Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); } @Override public void showProgress() { dialog = ProgressDialog.show(this, " ", "加载中", true, true); } @Override public void hideProgress() { dialog.dismiss(); } @Override public void showMessage(String msg) { Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); } }
看上面的代码,很简洁,没有任何逻辑代码,这就是我们想要的效果,接下来就开始写Presenter层了,逻辑代码也是写到这一层。
/** * Created by yuankundong on 2016/03/03. */ public interface LoginPresenter { void actionLogin(); }
实现:
/** * Created by yuankundong on 2016/03/03. */ public class LoginPresenterImpl implements LoginPresenter, OnLoginListener { LoginView loginView; LoginModel loginModel; public LoginPresenterImpl(LoginView loginView) { this.loginView = loginView; this.loginModel = new LoginModelImpl(); } @Override public void actionLogin() { String username = loginView.getUsername(); String password = loginView.getPassword(); if (TextUtils.isEmpty(username)) { loginView.showMessage("用户名为空"); return; } if (TextUtils.isEmpty(password)) { loginView.showMessage("密码为空"); return; } loginView.showProgress(); loginModel.toLogin(username,password,this); } @Override public void OnSuccess(UserBean userBean) { loginView.hideProgress(); loginView.loginSuccess(); } @Override public void OnError(int code, String msg) { loginView.hideProgress(); loginView.loginError(msg); } }
在LoginPresenterImpl 类中,我们实例了LoginView 和LoginModel 。登录的逻辑就是先判断用户名和密码是否为空,不为空再调用Model里的登录方法,进行登录。因为Model层把登录反馈传给OnLoginListener 这个回调接口,所有我们在这里实现这个接口,就能获取登录后的反馈。OnSuccess和OnError分别是登录成功和失败后,通知View层应该显示什么。
这样,我们用MVP写出来的登录就完成了,总体思想就是,Model层获取的数据交给Presenter处理,Presenter进行处理的过程中,会通知页面View层进行相应变化,View层本身不进行逻辑处理,MVP架构及时各有分工。
整体工程里面还有个别不涉及本文内容的我没有详述,源码地址,点击这里下载
相关文章推荐
- 礼拜五log~采用网站地址的方法获取栏目id
- Robot Framework 教程 (1) - 环境配置及简单网站兼容性测试
- 架构基础4-分布式缓存设计:一致性Hash算法
- 网站改版需要注意的优化问题
- 构建高并发高可用的电商平台架构实践
- Kubernetes基本术语与架构
- 2天内重复访问网站的用户个数,以IP个数为准
- 成长的记忆-为架构师之路记些东西
- web前端开发入门之网站布局
- 比较实用的网站
- web网站优化
- 秒杀系统架构分析与实战
- updata 网站的portfolio
- 搭建网站的一些问题
- 欺诈网站都注重用户体验!你,还在等什么?!
- 欺诈网站都注重用户体验!你,还在等什么?!
- 我在MDCC 2015的演讲PPT《HTML5移动应用多端开发架构实践》分享
- Discuz NT 架构剖析之Config机制
- 网站遭遇CC及DDOS攻击紧急处理方案
- 网站遭遇CC及DDOS攻击紧急处理方案