您当前的位置: 首页 >  android

暂无认证

  • 2浏览

    0关注

    98368博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

记一次重构:Android实践从MVC架构到MVP架构

发布时间:2016-12-08 13:34:04 ,浏览量:2

一直以来,想分享MVP的实战,因为很多项目开始并不是就是mvp架构的,可能是从传统的mvc结构变迁过来的。今天呈详给大家分享的这篇从mvc重构到mvp,让大家既能看到前后的对比,又能突出mvp的优点,呈详,目前在去哪儿网就职,同时也是csdn博客专家,他的blog地址:http://blog.csdn.net/p106786860.【阅读原文】,可看对应文章链接,话不多说,看下正文。

一、MVC

1.简介 MVC是目前大多数企业采用J2EE的结构设计,主要适用于交互式的Web应用。在Android中也有体现和使用,但是存在一定的弊端(下面将讲述),于是才有了Android官方推荐的MVP。 在Android的开发过程中,每个层对应如下:        Model层:对应Java Bean、Database、SharePreference和网络请求等;   View层:对应xml布局、自定义View或ViewGroup;       Controller层:对应Activity、Fragment; 2.实践 对于理论的理解 ,还是需要结合实际。下面我们将前面文章实现的https登录Demo,使用MVC的方式来进行重构: 项目结构:

View层: activity_login.xml

   
    
    
    
    
       
    

LoginInputView.java

public class LoginInputView extends LinearLayout {
    private TextView title;
    private EditText content;
    public LoginInputView(Context context, AttributeSet attrs) {
        super(context, attrs);
        LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        layoutInflater.inflate(R.layout.inputview_login, this);
        title = (TextView) findViewById(R.id.input_title);
        content = (EditText) findViewById(R.id.input_content);
    }
    /**
     * 设置输入项目的标题  
     * @param title 标题
     */
    public void setTitle(String title) {
        this.title.setText(title);
    }
    /**
     * 获取用户输入的内容
     * @return 用户输入的内容
     */
    public String getContent() {
        return content.getText().toString();
    }
}

Model层: LoginModel.java

public interface LoginModel {
    LoginResult loginByUserNameAndPassword(Context context, LoginParam loginParam);
}

LoginModelImp.java

public interface LoginModel {
    LoginResult loginByUserNameAndPassword(Context context, LoginParam loginParam);
}

Controller层: LoginActivity.java

public class LoginActivity extends AppCompatActivity implements View.OnClickListener {
    //View层渲染用户登录页面 组件
    private LoginInputView userNameInput;
    private LoginInputView passWordInput;
    private Button loginButton;
    private TextView responseTextView;
    //Modle层提封装了登录请求数据和行为
    private LoginModel loginModel;
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 1:
                    //Controller层获取Modle更新变化,选择到合适的视图更新显示
                    Bundle bundle = msg.getData();
                    LoginResult loginResult = (LoginResult) bundle.getSerializable("result");
                    responseTextView.setText(loginResult.getMessage());
                    break;
            }
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        userNameInput = (LoginInputView) findViewById(R.id.login_intput_username);
        passWordInput = (LoginInputView) findViewById(R.id.login_intput_password);
        loginButton = (Button) findViewById(R.id.login_login_button);
        responseTextView = (TextView) findViewById(R.id.login_result_text);
        loginButton.setOnClickListener(this);
        userNameInput.setTitle("UserName:");
        passWordInput.setTitle("PassWord:");
        loginModel = new LoginModelImp();
    }
    @Override
    public void onClick(View v) {
        //接受从View层获取的用户点击,分发到Controller处理
        responseTextView.setText("");
        //Controller层从View层选择视图,获取用户输入
        final String userName = userNameInput.getContent();
        final String passWorld = passWordInput.getContent();
        new Thread(new Runnable() {
            @Override
            public void run() {
                //Controller层将用户输入登录信息,发送到Model层执行登录相关逻辑
                LoginParam loginParam = new LoginParam(userName,passWorld);
                LoginResult loginResult = loginModel.loginByUserNameAndPassword(LoginActivity.this,loginParam);
                //Model层获取登录信息后,通知Controller层更新UI
                Message message = handler.obtainMessage();
                message.what = 1;
                Bundle bundle = new Bundle();
                bundle.putSerializable("result", loginResult);
                message.setData(bundle);
                handler.sendMessage(message);
            }
        }).start();
    }
}

运行结果:

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层,重构如下:

public class LoginActivity extends AppCompatActivity implements View.OnClickListener, LoginContract.View {
    private LoginInputView userNameInput;
    private LoginInputView passWordInput;
    private Button loginButton;
    private TextView responseTextView;
    private Handler handler = new LoginHander();
    private LoginContract.Presenter loginPesenter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        userNameInput = (LoginInputView) findViewById(R.id.login_intput_username);
        passWordInput = (LoginInputView) findViewById(R.id.login_intput_password);
        loginButton = (Button) findViewById(R.id.login_login_button);
        responseTextView = (TextView) findViewById(R.id.login_result_text);
        loginPesenter = new LoginPresenter(new LoginModelImp(), this);
    }
    @Override
    protected void onResume() {
        super.onResume();
        loginPesenter.start();
    }
    @Override
    public void onClick(View v) {
        loginPesenter.doLoginRequest(LoginActivity.this);
    }
    @Override
    public void setPresenter(LoginContract.Presenter presenter) {
        loginPesenter = presenter;
    }
    @Override
    public void initLoginShow() {
        userNameInput.setTitle("UserName:");
        passWordInput.setTitle("PassWord:");
        loginButton.setOnClickListener(this);
    }
    @Override
    public LoginParam getInputLoginParam() {
        final String userName = userNameInput.getContent();
        final String passWorld = passWordInput.getContent();
        LoginParam loginParam = new LoginParam(userName, passWorld);
        return loginParam;
    }
    @Override
    public void sendShowLoginMessage(LoginResult loginResult) {
        Message message = handler.obtainMessage();
        message.what = 1;
        Bundle bundle = new Bundle();
        bundle.putSerializable("result", loginResult);
        message.setData(bundle);
        handler.sendMessage(message);
    }
    @Override
    public void updateLoginResultByMessage(Message message) {
        Bundle bundle = message.getData();
        LoginResult loginResult = (LoginResult) bundle.getSerializable("result");
        updateLoginResultByString(loginResult.getMessage());
    }
    @Override
    public void updateLoginResultByString(String result) {
        responseTextView.setText(result);
    }
    /**
     * 登录Handler,处理来自子线程更新登录页面的消息
     */
    private class LoginHander extends Handler {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 1:
                    updateLoginResultByMessage(msg);
                    break;
            }
        }
    }
}

Presenter层: BasePresenter.java

public interface BasePresenter {
    void start();
}

BaseView.java

public interface BaseView{
    void setPresenter(T presenter);
}

LoginContract.java

public interface LoginContract {
    interface View extends BaseView{
        /**
         * 初始化登录页面显示
         */
        void initLoginShow();
        /**
         * 获取输入的登录参数
         */
        LoginParam getInputLoginParam();
        /**
         * 发送显示登录结果消息
         */
        void sendShowLoginMessage(LoginResult loginResult);
        /**
         * 通过消息更新登录结果
         */
        void updateLoginResultByMessage(Message message);
        /**
         * 更新登录结果信息
         */
        void updateLoginResultByString(String s);
    }
    interface Presenter extends BasePresenter {
        /**
         * 执行登录请求
         */
        void doLoginRequest(Context context);
    }
}

LoginPresenter.java

public class LoginPresenter implements LoginContract.Presenter {
    private final LoginModel loginModel;
    private final LoginContract.View loginView;
    public LoginPresenter(LoginModel loginModel, LoginContract.View loginView) {
        this.loginModel = loginModel;
        this.loginView = loginView;
        loginView.setPresenter(this);
    }
    @Override
    public void start() {
        loginView.initLoginShow();
    }
    @Override
    public void doLoginRequest(final Context context) {
        loginView.updateLoginResultByString("");
        new Thread(new Runnable() {
            @Override
            public void run() {
                LoginParam loginParam = loginView.getInputLoginParam();
                LoginResult loginResult = loginModel.loginByUserNameAndPassword(context, loginParam);
                loginView.sendShowLoginMessage(loginResult);
            }
        }).start();
    }
}

3.优点   降低耦合度,实现了Model和View真正的完全分离,可以修改View而不影响Model;   Activity只处理生命周期的任务,代码变得简洁; 4.代码库 QProject:https://github.com/Pengchengxiang/QProject  分支:feature/mvc_mvp

第一时间获得博客更新提醒,以及更多android干货,源码分析,欢迎关注我的微信公众号,扫一扫下方二维码或者长按识别二维码,即可关注。

关注
打赏
1655516835
查看更多评论
立即登录/注册

微信扫码登录

0.2187s