专栏名称: 开发者全社区
分享和推送Java/Android方向的技术和文章,让你成为这方面的大牛,让你每天都成长一点。同时,我们也会邀请BAT的大牛分享原创!
目录
相关文章推荐
鸿洋  ·  Android H5页面性能分析策略 ·  2 天前  
鸿洋  ·  AndroidManifest中uses-l ... ·  6 天前  
鸿洋  ·  Android | 扩大View点击区域的几种方式 ·  1 周前  
51好读  ›  专栏  ›  开发者全社区

APP重构:Android实践从MVC架构到MVP架构

开发者全社区  · 公众号  · android  · 2016-12-19 11:30

正文

来源:http://blog.csdn.net/p106786860/article/details/53439421

相关阅读:

吊炸天!74款APP完整源码!

2016年未,腾讯,百度,华为,搜狗和滴滴Android面试题汇总


一直以来,想分享MVP的实战,因为很多项目开始并不是就是mvp架构的,可能是从传统的mvc结构变迁过来的。今天呈详给大家分享的这篇从mvc重构到mvp,让大家既能看到前后的对比,又能突出mvp的优点。

一、MVC

1.简介

MVC是目前大多数企业采用J2EE的结构设计,主要适用于交互式的Web应用。在Android中也有体现和使用,但是存在一定的弊端(下面将讲述),于是才有了Android官方推荐的MVP。



View层:
activity_login.xml


LoginInputView.java


Model层:
LoginModel.java

  1. public interface LoginModel {

  2.    LoginResult loginByUserNameAndPassword(Context context, LoginParam loginParam);

  3. }

LoginModelImp.java

  1. public interface LoginModel {

  2.    LoginResult loginByUserNameAndPassword(Context context, LoginParam loginParam);

  3. }

Controller层:
LoginActivity.java

  1. public class LoginActivity extends AppCompatActivity implements View.OnClickListener {

  2.    //View层渲染用户登录页面 组件

  3.    private LoginInputView userNameInput;

  4.    private LoginInputView passWordInput;

  5.    private Button loginButton;

  6.    private TextView responseTextView;

  7.    //Modle层提封装了登录请求数据和行为

  8.    private LoginModel loginModel;

  9.    private Handler handler = new Handler() {

  10.        @Override

  11.        public void handleMessage(Message msg) {

  12.            super.handleMessage(msg);

  13.            switch (msg.what) {

  14.                case 1:

  15.                    //Controller层获取Modle更新变化,选择到合适的视图更新显示

  16.                    Bundle bundle = msg.getData();

  17.                    LoginResult loginResult = (LoginResult) bundle.getSerializable("result");

  18.                    responseTextView.setText(loginResult.getMessage());

  19.                    break;

  20.            }

  21.        }

  22.    };

  23.    @Override

  24.    protected void onCreate(Bundle savedInstanceState) {

  25.        super.onCreate(savedInstanceState);

  26.        setContentView(R.layout.activity_login);

  27.        userNameInput = (LoginInputView) findViewById(R.id.login_intput_username);

  28.        passWordInput = (LoginInputView) findViewById(R.id.login_intput_password);

  29.        loginButton = (Button) findViewById(R.id.login_login_button);

  30.        responseTextView = (TextView) findViewById(R.id.login_result_text);

  31.        loginButton.setOnClickListener(this);

  32.        userNameInput.setTitle("UserName:");

  33.        passWordInput.setTitle("PassWord:");

  34.        loginModel = new LoginModelImp();

  35.    }

  36.    @Override

  37.    public void onClick(View v) {

  38.        //接受从View层获取的用户点击,分发到Controller处理

  39.        responseTextView.setText("");

  40.        //Controller层从View层选择视图,获取用户输入

  41.        final String userName = userNameInput.getContent();

  42.        final String passWorld = passWordInput.getContent();

  43.        new Thread(new Runnable() {

  44.            @Override

  45.            public void run() {

  46.                //Controller层将用户输入登录信息,发送到Model层执行登录相关逻辑

  47.                LoginParam loginParam = new LoginParam(userName,passWorld);

  48.                LoginResult loginResult = loginModel.loginByUserNameAndPassword(LoginActivity.this,loginParam);

  49.                //Model层获取登录信息后,通知Controller层更新UI

  50.                Message message = handler.obtainMessage();

  51.                message.what = 1;

  52.                Bundle bundle = new Bundle();

  53.                bundle.putSerializable("result", loginResult);

  54.                message.setData(bundle);

  55.                handler.sendMessage(message);

  56.            }

  57.        }).start();

  58.    }

  59. }

运行结果:


3.优点


  Controller层起到桥梁作用,在View层和Model层之间通信,使得View层和Modle层分离解耦;


4.缺点


  然而,在Android中由于View层的XML控制太弱,Controler层的Activity并没有和View层完全分离。当需要动态改变一个页面的显示(如背景、显示隐藏按钮等),都无法在xml中处理,只能在Activity中处理。造成了Activity即时Controller层又是View层,代码繁冗。

二、MVP


1.简介


  MVP模式是MVC模式在Android上的一种变体。在MVC中Activity应该是属于Controller层,而实质上,它即承担了Contrller,也包含了许多View层的逻辑在里面。把Activity中的UI逻辑抽象成View接口,把业务逻辑抽象成Presenter接口,Model类还是原来的Model,这就是MVP;

Model层:同MVC,负责处理数据加载或者存储,如从网络或者数据库获取数据等;
View层:处理数据展示,用户的交互。在MVP中Activity,Fragment属于该层;
Presenter层:是Model层和View层的桥梁,从Model层中获取数据,展示在View层;

2.实践


项目结构:

Model层:同上mvc
View层:同上mvc,但activity在mvp中为view层,重构如下:

  1. public class LoginActivity extends AppCompatActivity implements View.OnClickListener, LoginContract.View {

  2.    private LoginInputView userNameInput;

  3.    private LoginInputView passWordInput;

  4.    private Button loginButton;

  5.    private TextView responseTextView;

  6.    private Handler handler = new LoginHander();

  7.    private LoginContract.Presenter loginPesenter;

  8.    @Override

  9.    protected void onCreate(Bundle savedInstanceState) {

  10.        super.onCreate(savedInstanceState);

  11.        setContentView(R.layout.activity_login);

  12.        userNameInput = (LoginInputView) findViewById(R.id.login_intput_username);

  13.        passWordInput = (LoginInputView) findViewById(R.id.login_intput_password);

  14.        loginButton = (Button) findViewById(R.id.login_login_button);

  15.        responseTextView = (TextView) findViewById(R.id.login_result_text);

  16.        loginPesenter = new LoginPresenter(new LoginModelImp(), this);

  17.    }

  18.    @Override

  19.    protected void onResume() {

  20.        super.onResume();

  21.        loginPesenter.start();

  22.    }

  23.    @Override

  24.    public void onClick(View v) {

  25.        loginPesenter.doLoginRequest(LoginActivity.this);

  26.    }

  27.    @Override

  28.    public void setPresenter(LoginContract.Presenter presenter) {

  29.        loginPesenter = presenter;

  30.    }

  31.    @Override

  32.    public void initLoginShow() {

  33.        userNameInput.setTitle("UserName:");

  34.        passWordInput.setTitle("PassWord:");

  35.        loginButton.setOnClickListener(this);

  36.    }

  37.    @Override

  38.    public LoginParam getInputLoginParam() {

  39.        final String userName = userNameInput.getContent();

  40.        final String passWorld = passWordInput.getContent();

  41.        LoginParam loginParam = new LoginParam(userName, passWorld);

  42.        return loginParam;

  43.    }

  44.    @Override

  45.    public void sendShowLoginMessage(LoginResult loginResult) {

  46.        Message message = handler.obtainMessage();

  47.        message.what = 1;

  48.        Bundle bundle = new Bundle();

  49.        bundle.putSerializable("result", loginResult);

  50.        message.setData(bundle);

  51.        handler.sendMessage(message);

  52.    }

  53.    @Override

  54.    public void updateLoginResultByMessage(Message message) {

  55.        Bundle bundle = message.getData();

  56.        LoginResult loginResult = (LoginResult) bundle.getSerializable("result");

  57.        updateLoginResultByString(loginResult.getMessage());

  58.    }

  59.    @Override

  60.    public void updateLoginResultByString(String result) {

  61.        responseTextView.setText(result);

  62.    }

  63.    /**

  64.     * 登录Handler,处理来自子线程更新登录页面的消息

  65.     */

  66.    private class LoginHander extends Handler {

  67.        @Override

  68.        public void handleMessage(Message msg) {

  69.            super.handleMessage(msg);

  70.            switch (msg.what) {

  71.                case 1:

  72.                    updateLoginResultByMessage(msg);

  73.                    break;

  74.            }

  75.        }

  76.    }

  77. }

Presenter层:
BasePresenter.java

  1. public interface BasePresenter {

  2.    void start();

  3. }

BaseView.java

  1. public interface BaseView {

  2.    void setPresenter(T presenter);

  3. }

LoginContract.java

  1. public interface LoginContract {

  2.    interface View extends BaseViewPresenter> {

  3.        /**

  4.         * 初始化登录页面显示

  5.         */

  6.        void initLoginShow();

  7.        /**

  8.         * 获取输入的登录参数

  9.         */

  10.        LoginParam getInputLoginParam();

  11.        /**

  12.         * 发送显示登录结果消息

  13.         */

  14.        void sendShowLoginMessage(LoginResult loginResult);

  15.        /**

  16.         * 通过消息更新登录结果

  17.         */

  18.        void updateLoginResultByMessage(Message message);

  19.        /**

  20.         * 更新登录结果信息

  21.         */

  22.        void updateLoginResultByString(String s);

  23.    }

  24.    interface Presenter extends BasePresenter {

  25.        /**

  26.         * 执行登录请求

  27.         */

  28.        void doLoginRequest(Context context);

  29.    }

  30. }

LoginPresenter.java

  1. public class LoginPresenter implements LoginContract.Presenter {

  2.    private final LoginModel loginModel;

  3.    private final LoginContract.View loginView;

  4.    public LoginPresenter(LoginModel loginModel, LoginContract.View loginView) {

  5.        this.loginModel = loginModel;

  6.        this.loginView = loginView;

  7.        loginView.setPresenter(this);

  8.    }

  9.    @Override

  10.    public void start() {

  11.        loginView.initLoginShow();

  12.    }

  13.    @Override

  14.    public void doLoginRequest(final Context context) {

  15.        loginView.updateLoginResultByString("");

  16.        new Thread(new Runnable() {

  17.            @Override

  18.            public void run() {

  19.                LoginParam loginParam = loginView.getInputLoginParam();

  20.                LoginResult loginResult = loginModel.loginByUserNameAndPassword(context, loginParam);

  21.                loginView.sendShowLoginMessage(loginResult);

  22.            }

  23.        }).start();

  24.    }

  25. }




关于Java和Android大牛频道

Java和Android大牛频道是一个数万人关注的探讨Java和Android开发的公众号,分享和原创最有价值的干货文章,让你成为这方面的大牛!

我们探讨android和Java开发最前沿的技术:android性能优化 ,插件化,跨平台,动态化,加固和反破解等,也讨论设计模式/软件架构等。由群来自BAT的工程师组成的团队

关注即送红包,回复:“百度” 、“阿里”、“腾讯” 有惊喜!!!关注后可用入微信群。群里都是来自百度阿里腾讯的大牛。

欢迎关注我们,一起讨论技术,扫描和长按下方的二维码可快速关注我们。搜索微信公众号:JANiubility。

公众号:JANiubility