zoukankan      html  css  js  c++  java
  • Android中的MVP架构初探

    说来羞愧,MVP的架构模式已经在Android领域出现一两年了。可是到今天自己才開始Android领域中的MVP架构征程。

    闲话不多说,開始吧。

    一、架构演变概述

    我记得我找第一份工作时,面试官问我“android是否属于MVC架构模式,简述一下”。确实,Android的总体设计结构就是MVC的设计模式。在J2EE的开发中,使用的也是MVC模式,MVC模式是一个经典,经历了几十年的考验。Android项目中的MVC架构:

    • View:是应用程序中处理数据显示的部分。相应于layout文件下的布局文件
    • Model:业务逻辑和实体模型
    • Controllor:是应用程序中处理用户交互的部分。Activity来充当。

    看似分工明白,可是也给我们带来了不少问题,假设一个页面的业务逻辑很复杂,我们的Activty须要大量的逻辑处理代码,使得Activity既像View又像Controllor,又当爹又当妈。工作量很大。

    造成代码的阅读星很差。

    为了解决问题。MVP模式就在Android领域诞生了。补充:我查看资料发现MVP模式最早是微软设计出来的,应用在Visual Stuido平台,不得不说微软尽管闭源,可是很niubility。

    二、MVP概述

    mvp

    上面的图。精炼的概述了MVP架构之间的通讯流程。在android中。

    • 模型(Model):业务逻辑处理,负责处理数据的载入或者存储,比方从网络或本地数据库获取数据等。
    • 视图(View):负责界面数据的展示,与用户进行交互,就是Activity。
    • 主导器(Presenter):相当于协调者。是模型与视图之间的桥梁。将模型与视图分离开来。通过Presenter进行它们之间的交互,隔离了M、V之间的直接交互。

    这种架构。就让我们的Activity更像View,减少了M、V之间的耦合度。

    三、MVP实践

    我们先看下我们的效果图:

    logo

    这是一个简答的登陆页面,在这个登陆页面中,我们就触发一个事件,就是点击登陆事件。我们先看看我们的project组织架构。

    structure

    我们分别创建了:bean、model、presenter、view四个包。为了解放Activity,我们把曾经Activity里的大量逻辑进行拆分。

    1、bean包

    我们创建实体UserBean,用来存放我们的用户信息。这个没什么说的。

        public class UserBean implements Parcelable{
            private String name;
            private String password;
    
            public UserBean(){
    
            }
    
            public String getName() {
                return name;
            }
    
            public void setName(String name) {
                this.name = name;
            }
    
            public String getPassword() {
                return password;
            }
    
            public void setPassword(String password) {
                this.password = password;
            }
    
            @Override
            public int describeContents() {
                return 0;
            }
            @Override
            public void writeToParcel(Parcel dest, int flags) {
                dest.writeString(name);
                dest.writeString(password);
            }
        }

    2、view包

    我们首先从View(视图层)看,view包下存放了我们视图层中的操作,它不涉及不论什么业务逻辑。主要是针对我们的页面进行数据的获取与设置

    我们针对这个登陆功能。进行分析:

    • 姓名和密码的获取
    • 姓名和密码的保存

    我们抽取出页面View层须要做的事情。接下来我们定义一个IUserView接口,里面包括我们抽取出来的方法。

        /**
         * 抽离View层。用于View页面的数据获取之类
         * @author Administrator
         *
         */
        public interface IUserView {
            public String getUserName();
            public String getUserPsd();
        }

    我们仅仅进行了获取,没有做保存。总结:View层的任务就是抽象页面的数据,提取出来写成方法。

    3、model包

    在view层,我们的数据获取有了着落,如今我们就開始处理我们的业务逻辑。依据页面得知,我们就模拟一个登陆功能。所以它就一个登陆事件。

    我们创建IUserModel接口用于包括我们处理的业务逻辑。

        /**
         * 业务逻辑处理
         * @author Administrator
         *
         */
        public interface IUserModel {
            /**
             *提取的一个登陆方法。当然还能够有其他方法。比方获取数据,保存用户信息之类
             * @param name  username
             * @param pwd   密码
             * @param loginListener 登陆监听
             */
            public void login(String name,String pwd,ILoginListener loginListener);
        }

    有了业务逻辑的接口规范。我们还须要去实现它,给与我们想要的逻辑。所以就有了UserModel类:

        public class UserModel implements IUserModel{
    
            @Override
            public void login(String name, String pwd, ILoginListener loginListener) {
                if(TextUtils.isEmpty(name) || TextUtils.isEmpty(pwd)){
                    loginListener.onError();
                    return;
                }
    
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if("dsw".equals(name) && "123".equals(pwd)){
                    loginListener.onSucess();
                }else{
                    loginListener.onFail();
                }
            }
        }

    我们为了方便我们对业务逻辑处理的监听,所以我们创建了一个接口,用来推断我们的登陆事件。

        /**
         * 登陆接口的监听,方便我们在View层中控制,便于给出提示
         * @author Administrator
         *
         */
        public interface ILoginListener {
            //登陆成功
            public void onSucess();
            //登陆失败
            public void onFail();
            //数据不完毕
            public void onError();
        }

    我们用来监听业务处理的推断。比方成功了我们弹出一个Toast之类的。

    4、presenter包

    数据有了,对数据的业务处理也有了。这里我们的Presenter就闪灵登场了。记住是Presenter、Presenter、Presenter(重要的东西说三次)。它用来连接我们的M、V层,让二者打通任督二脉实现整个流程。所以为了实现二者的联系。它的内部必定会有M、V的实例。来看看IUserPresenter:

        public class IUserPresenter {
            //数据源
            private IUserView userView;
            //处理业务逻辑
            private IUserModel userModel;
    
            public IUserPresenter(IUserView userView){
                this.userView = userView;
                userModel = new UserModel();
            }
    
            /**
             * 登陆方法。进行M,V层的关系建立
             * @param loginListener
             */
            public void login(ILoginListener loginListener){
                userModel.login(userView.getUserName(), userView.getUserPsd(), loginListener);
            }
        }

    我们仅仅须要在Activity中创建一个IUserPresenter类,然后调用login方法进行登录就可以。

    在这段代码中。IUserView是我们的数据源,我们通过它的方法用于从页面获取数据,所以我们的Activity必须实现这个IUserView接口,然后传递给IUserPresenter。在IUserPresenter中调用IUserModel的实现业务逻辑的处理。

    5、最后的Activity处理

        public class MainActivity extends Activity implements IUserView {
            private EditText et_name,et_pwd;
            private Button btn_login;
            //指示器与View层进行交互
            private IUserPresenter userPresenter;
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
                et_name = (EditText) findViewById(R.id.et_name);
                et_pwd = (EditText) findViewById(R.id.et_psw);
                btn_login = (Button) findViewById(R.id.btn_login);
                userPresenter = new IUserPresenter(this);
                btn_login.setOnClickListener(new OnClickListener() {
    
                    @Override
                    public void onClick(View v) {
                        userPresenter.login(loginListener);
                    }
                });
            }
            @Override
            public String getUserName() {
                return et_name.getText().toString();
            }
            @Override
            public String getUserPsd() {
                return et_pwd.getText().toString();
            }
    
            /**
             * 登陆监听接口
             */
            private ILoginListener loginListener = new ILoginListener() {
    
                @Override
                public void onSucess() {
                    Toast.makeText(getApplication(), "登陆成功", Toast.LENGTH_SHORT).show();
                }
    
                @Override
                public void onFail() {
                    Toast.makeText(getApplication(), "登陆失败", Toast.LENGTH_SHORT).show();        
                }
    
                @Override
                public void onError() {
                    Toast.makeText(getApplication(), "数据不完整,请又一次输入", Toast.LENGTH_SHORT).show();
                }
            };
        }

    在activity中,我们实现IUserView接口,来实现该view层的数据获取。

    然后创建IUserPresenter类。调用login方法进行登录。同一时候实现对业务逻辑的处理监听。

    至此。我们就完毕了整个的流程。看看我们的效果图:

    mvpresult

    源代码本来打算上传的熬csdn的,结果上传不了,所以果断github
    强烈建议大家手动敲一遍代码,加深理解。

    总结图:

    conclusion

    ==========================================================
    作者:mr_dsw

    转载注明出处,分享是进步的源泉。

    ==========================================================

  • 相关阅读:
    在IIS7.5中ASP.NET调用cmd程序拒绝访问决绝方法小记
    WindowsCE project missing Microsoft.CompactFramework.CSharp.targets in Visual Studio 2008
    Windows 10预览版14316开启Bash命令支持
    批量文件重命名工具
    多说使用ua-parser-js显示浏览器和系统信息
    Hexo主题实现多级分类显示
    MS SQL Server 数据库分离-SQL语句
    Windows应用程序快捷方式创建工具
    第三方登录插件.NET版XY.OAuth-CSharp
    Microsoft Visual Studio 2008 未能正确加载包“Visual Web Developer HTML Source Editor Package” | “Visual Studio HTM Editor Package”
  • 原文地址:https://www.cnblogs.com/yjbjingcha/p/7133225.html
Copyright © 2011-2022 走看看