写在前边架构
小伙伴们,两天不见了,很想念大家哦!这两天一直没来得及更新,由于最近在研究 Android 的 MVP 架构,我以为这也是一个重要的 Android 进阶的技术点。框架
昨天我还问我身边的小伙伴,我问他 “你知道咱们学的 Android 有哪些架构吗?” 他一脸懵逼的告诉我 “你还别说,Android 的架构我还真不知道。” 他也不算是小白了,学了 Android 也有一年了,正是当年和我一块儿从安卓基础学到如今的一个小伙伴。而后我经过这几天的架构学习简单和他讲了一下,他当时恍然大悟。ide
这就说明一个状况,你不去主动去学习了解这些与 Android 相关技术点,总会被慢慢淘汰的。个人这个小伙伴估计是淘汰不了了,哈哈,他身边有我指点着呢!post
我充分利用这两天的空余时间,经过查看文档和博客的学习,完全的理解了 MVP 架构的结构。而后把手头的项目用 MVP 架构作了一遍,也算是入坑了。 学习
从公众号一开始关注个人读者知道,我不会为了发文章而写文章的,若是手头真没有值得分享的技术文章,我是不会随便写一篇来应付过去的。从我我的的写做经验能够得出,一篇真正有价值,让别人可以学习到真正有养分的技术的一篇文章从起草到构思,再到总结整理,最后排版直到成功分享到公众号至少须要两个多小时甚至还不够。曾经我也作过实验,把一篇技术文用一个小时迅速完成,读者的收获每每没有,阅读量惨淡,读者的脑子里对这个技术点只是一个大致的框架。读者若是真想借助文章的肩膀往上爬,这还对写文章的做者有很严格的要求的。虽然如今作公众号的人多了,可是,像张哥说的同样,高质量的文章仍是屈指可数的。一味地坚持天天发文,你是否考虑到文章的质量呢?废话很少说,直接上 MVP 架构,今天说啥也让你弄懂。this
正文线程
介绍 MVP 架构以前,如今简单了解一下MVC 架构,M『 Model 模型层』V『 View 视图层』C『 Control 控制层』。MVC 架构是一个很适合初学者入门的架构,作 Servlet 后台服务用的比较多,如今公司基本用 ssm 框架作开发了。MVC 这里很少深刻介绍,想要了解,网上不少文档供参考学习。在 Android中 MVC 架构其实不经常使用,也不适合用。由于 View 视图层和 Control 控制层的代码都在整个 Activity 中实现的,不能清晰的展示出 View 层和 Control 控制层的所要处理的功能的分离。因此咱们 Android 进一步对 MVC 进行改进,就演化成了如今经常使用到的 MVP 架构 M『 Model 模型层』V『 View 视图层』P『 Presenter 层』Presenter 用英语翻译过来就是表明者的意思。他在 MVP 架构中起到什么做用呢?它的做用就是链接 View 层和 Model 层的的桥梁。说白了就是,他是一根电话线,保持两端的通讯。MVP 和 MVC 的另外一个区别就是,Model 层和 View 视图层不能直接通讯,而是经过这个 Presenter 这根线的链接才能通讯。以前的 MVC 呢?就不能把 Control 控制层看作成电话线了,而是看作成处理逻辑的一个类,View 层和 Control 层还有 Model 层两两互相能够通讯,三者之间的数据传输能够很随意没有限制。回过头来再看 MVP 架构,Model 层和 View 层的数据都会传到 Presenter 层作二者的处理。写到这里不懂没关系,下面会具体说明。翻译
咱们再来看一组示意图:调试
MVC 结构示意图:code
MVP 结构示意图
是否是对这两个架构的区分又清晰了一步?
有小伙伴要着急了,兄弟别废话了,直接上代码吧,别来说这些概念了。上边这些概念是让你脑子里造成一个大致的框架,对 MVP 架构有一个基本的认识,才会对下边要举的例子有个清晰的认识。
用 MVP 架构写一个用户登陆的例子吧!
第一步 : 包的目录分布
总目录 :
分目录 :
第二步 : Model层
User 类属于 bean,为数据类:
1public class User { 2 private String username ; 3 private String password ; 4 public String getUsername() { 5 return username; 6 } 7 public void setUsername(String username) { 8 this.username = username; 9 } 10 public String getPassword() { 11 return password; 12 } 13 public void setPassword(String password) { 14 this.password = password; 15 } 16}
IOnLoginListener 为「判断登陆是否成功」的接口:
1public interface IOnLoginListener { 2 //登陆成功 3 void loginSuccess(User user); 4 //登陆失败 5 void loginFailed(); 6}
IUserImp 为登陆功能的接口:
1public interface IUserImp { 2 //登陆 3 public void login(String username, String password, IOnLoginListener loginListener); 4}
UserImp 为 IUserImp 接口的实现类:
1public class UserImp implements IUserImp { 2 @Override 3 public void login(final String username, final String password, final IOnLoginListener loginListener) { 4 //模拟子线程耗时操做 5 new Thread() { 6 @Override 7 public void run() { 8 try { 9 Thread.sleep(2000); 10 } catch (InterruptedException e) { 11 e.printStackTrace(); 12 } 13 //模拟登陆成功 14 if ("zhy".equals(username) && "123".equals(password)) { 15 User user = new User(); 16 user.setUsername(username); 17 user.setPassword(password); 18 loginListener.loginSuccess(user); 19 } else { 20 loginListener.loginFailed(); 21 } 22 } 23 }.start(); 24 } 25}
第三步 : View视图层
View 中的 IUserLoginView 为实现与 UI 交互的的方法接口:
1public interface IUserLoginView { 2 //View获取用户名和密码 3 String getUserName(); 4 String getPassword(); 5 //清除用户名和密码 6 void clearUserName(); 7 void clearPassword(); 8 //耗时提示ProgressBar 9 void showLoading(); 10 void hideLoading(); 11 //提醒 登陆成功失败 12 void toMainActivity(User user); 13 void showFailedError(); 14}
第四步 : Presenter 层
Persenter 类中的做用来链接 View 层和 Model 层的:
1public class UserLoginPresenter { 2 private IUserImp userBiz; 3 private IUserLoginView userLoginView; 4 private Handler mHandler = new Handler(); 5 public UserLoginPresenter(IUserLoginView userLoginView) { 6 this.userLoginView = userLoginView; 7 this.userBiz = new UserImp(); 8 } 9 public void login() { 10 userLoginView.showLoading(); 11 userBiz.login(userLoginView.getUserName(), userLoginView.getPassword(), new IOnLoginListener() { 12 @Override 13 public void loginSuccess(final User user) { 14 //须要在UI线程执行 15 mHandler.post(new Runnable() { 16 @Override 17 public void run() { 18 userLoginView.toMainActivity(user); 19 userLoginView.hideLoading(); 20 } 21 }); 22 } 23 @Override 24 public void loginFailed() { 25 //须要在UI线程执行 26 mHandler.post(new Runnable() { 27 @Override 28 public void run() { 29 userLoginView.showFailedError(); 30 userLoginView.hideLoading(); 31 } 32 }); 33 } 34 }); 35 } 36 public void clear() { 37 userLoginView.clearUserName(); 38 userLoginView.clearPassword(); 39 } 40}
第五步 : LoginActivity 去实现登陆功能
1public class UserLoginActivity extends Activity implements IUserLoginView{ 2 private EditText mEtUsername,mEtPassword; 3 private Button mBtnClear,mBtnLogin; 4 private ProgressBar mPbLoading; 5 private UserLoginPresenter mUserLoginPresenter = new UserLoginPresenter(this); 6 @Override 7 protected void onCreate(@Nullable Bundle savedInstanceState) { 8 super.onCreate(savedInstanceState); 9 setContentView(R.layout.activity_main); 10 initViews(); 11 } 12 private void initViews() 13 { 14 mEtUsername = (EditText) findViewById(R.id.id_et_username); 15 mEtPassword = (EditText) findViewById(R.id.id_et_password); 16 mBtnClear = (Button) findViewById(R.id.id_btn_clear); 17 mBtnLogin = (Button) findViewById(R.id.id_btn_login); 18 mPbLoading = (ProgressBar) findViewById(R.id.id_pb_loading); 19 //登陆 20 mBtnLogin.setOnClickListener(new View.OnClickListener() { 21 @Override 22 public void onClick(View v) { 23 mUserLoginPresenter.login(); 24 } 25 }); 26 //取消登陆 27 mBtnClear.setOnClickListener(new View.OnClickListener() { 28 @Override 29 public void onClick(View v) { 30 mUserLoginPresenter.clear(); 31 } 32 }); 33 } 34 @Override 35 public String getUserName() { 36 return mEtUsername.getText().toString(); 37 } 38 @Override 39 public String getPassword() { 40 return mEtPassword.getText().toString(); 41 } 42 @Override 43 public void clearUserName() { 44 mEtUsername.setText(""); 45 } 46 @Override 47 public void clearPassword() { 48 mEtPassword.setText(""); 49 } 50 @Override 51 public void showLoading() { 52 mPbLoading.setVisibility(View.GONE); 53 } 54 @Override 55 public void hideLoading() { 56 mPbLoading.setVisibility(View.VISIBLE); 57 } 58 @Override 59 public void toMainActivity(User user) { 60 Toast.makeText(this, user.getUsername() + 61 " login success , to MainActivity", Toast.LENGTH_SHORT).show(); 62 } 63 @Override 64 public void showFailedError() { 65 Toast.makeText(this, 66 "login failed", Toast.LENGTH_SHORT).show(); 67 } 68}
当初我学习这个架构的时候有点懵逼,各类你接口各类实现类,弄得我晕头转向的。我就一直看一直琢磨,相信最后总会看会的,这些努力和付出最终让我完全明白了这个叫 MVP 的架构。我给你们提供一个好的方法,经过断点调试,一步步跟着程序运行,这样就很容易明白的知道整个架构的逻辑和流程。
咱们经过上边的一系列学习,有的小伙伴就要问了,怎么一个简单的登陆系统怎么代码量变多了?没错,代码量是变多了,你有没有感受到项目逻辑架构清晰了不少?并且每一个架构层中的每一个类都要执行的规定好的任务『 View 视图层主要管与 UI 界面作交互的(如:监听用户按钮事件);Model 模型层主要是管理数据对象的;Presenter 层主要管理 Model 和 View 的数据通讯处理逻辑运算的』。这种架构作小项目是体现不出有优势的,等之后到了公司开发大型的项目,代码量成千上万,MVP 架构的优点就很明了的展示出来,并且包括后期的项目维护,这种优点相比把代码写到一个 Activity 里边要好的多。好比公司的项目要加一个功能,按照往常的作法,先把整个 Activity 里边的逻辑理清,当你理清逻辑,估计公司的黄花菜都凉凉了。然而用 MVP 架构呢,你能够准确的找到实现该功能的接口,随意的添加该方法到里边,找到实现该方法的实现类而后实现该功能就 ok 了。只有你真正的去作了,才能体会到这种架构的好处,只听我在这说 bb 没什么软用的。
好了,这两天我就主要了解了 MVP 架构,有什么不足可在后台留言我后期会补充。
后记
为了今天可以给你们更新干货,这些大部分都是在上午上课的时候总结的。作一篇干货文章真的不容易,这篇文章从开始写到发布到公众号你还被不信,我算了算加起来先后用了三个半小时来更新这篇文章。公众号高质量的文章也愈来愈少,都是为了利益绝不顾忌的更新低质量的文章。利益互推、瞎转发几乎成了一种常态,我但愿个人公众号一直能这样高质量的输出干货,经过本身理解总结整合分析反思推敲琢磨,努力打造一个独一无二纯净的公众号。