美文网首页
Android MVP的简单实现

Android MVP的简单实现

作者: JokerHerry | 来源:发表于2017-11-28 20:21 被阅读0次

    一个好的好的设计模式可以帮我们很好的管理我们的代码,也会方便于我们的后期的扩展。特别是针对我们这样的新手,学好一个好的代码管理是很有必要的。所以今天,和大家一起学习一下MVP模式。

    一、MVP设计模式概述

    什么是MVP设计模式

    MVP,分别是Model-View-Presenter,即模型-视图-提出者。
    Model:模型,实现业务逻辑和实例生成。
    View:视图,对应的界面布局,以及界面布局的方法。
    Presenter:一个活动中,主要的业务交互,作为view和model的中间传达者。

    什么是MVC设计模式

    MVP,分别是Model-View-Presenter,即模型-视图-控制器。
    Model:模型,实现业务逻辑和实例生成。
    View:视图,对应的界面布局,以及界面布局的方法。
    Controllor:作为页面的控制器,响应view的交互,对应于Android中的Activity

    对比

    这么说可能不是很清晰,我们用两张图片来描述一下。


    MVP与MVC对比

    但是在Android我们的可以知道,其实Avtivity不仅要处理view的呈现,还要负责处理页面的业务逻辑,显得Activity不仅像view,又像controllor的结合体,导致Acitivity整体臃肿,超过1000行都是常事。

    所以,为了更好的解耦这样的情况,让Activity更好的只关心页面的呈现,将主要的业务交互放置在presenter中实现,让Presenter作为view与model的中间传递者。减少Activity的体积。降低耦合度。

    在MVP模式中,我们要做到,view层和model不能直接通信,要想通信,必须通过Persenter这一中间件。并且,view,model,presenter都是接口,之间的通讯也都是通过接口实现的。

    二、 MVP的简单实现

    接下来我们通过一个基础的实例,让我们来实现一个简单的MVP模式的登录界面。从实例的角度,我们来分析一个具体的MVP模式。看看他是怎样实现解耦,以及明显的内容划分。

    Model层:

    model层是用来实现某一层里面的业务逻辑。
    那么,在一个登录界面中,我的model层就是实现登录密码检验的功能。
    首先,我们需要有一个对象类,来表达我们需要检验的对象。

    public class User {
        private String name;
        private String password;
    
        public User(String name,String password){
            this.name = name;
            this.password = password;
        }
        ...省略getter和setter
    }
    

    然后我们需要一个LoginModel的接口函数,来申明我们的登录所需要的函数。

    public interface LoginModel {
        void login(User user);
    }
    

    其次是model的实现类,实现我们刚才在LoginModel中申明的login函数。
    这里我们延时2秒钟,用于模拟登陆效果。

    public class LoginModelImpl implements LoginModel{
        @Override
        public void login(User user) {
            final String name = user.getName();
            final String password = user.getPassword();
    
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    Boolean error =false;
                    if (TextUtils.isEmpty(name)){
                        error = true;
                        //输入错误
                        System.out.println("输入错误");
                    }
                    if (TextUtils.isEmpty(password)){
                        error = true;
                        //输入错误
                        System.out.println("输入错误");
                    }
                    if(!error){
                        //登录成功
                        System.out.println("登录成功");
                    }
                }
            },2000);
        }
    }
    

    View层:

    对应的界面布局,以及界面布局的方法。
    这里我们需要实现的waitDialog的显示与消失,以及登录成功和失败的提醒,所以建立我们的view接口类,LoginView.

    public interface LoginView {
        void loginSuccess();
        void ErrorPass();
        void ErrorEnter();
    
        void showDialog();
        void hideDialog();
    }
    

    然后我们的实例就是Activity,使Acitivity继承我们的接口,实现我们接口中的方法。

        //申明persenter实例
        LoginPresenter presenter;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_login);
            ButterKnife.bind(this);
    
            btn.setOnClickListener(this);
            //通过Presenter实例类申明presenter
            presenter = new LoginPresenterImpl(this);
        }
        
    
        @Override
        public void loginSuccess() {
            Toast.makeText(this,"登录成功",Toast.LENGTH_SHORT).show();
        }
    
        @Override
        public void ErrorPass() {
            Toast.makeText(this,"密码错误",Toast.LENGTH_SHORT).show();
        }
    
        @Override
        public void ErrorEnter() {
            Toast.makeText(this,"输入错误",Toast.LENGTH_SHORT).show();
        }
    
        @Override
        public void showDialog() {
            loginProgress.setVisibility(View.VISIBLE);
        }
    
        @Override
        public void hideDialog() {
            loginProgress.setVisibility(View.GONE);
        }
        
        @Override
        public void onClick(View v) {
            User user = new User(name.getText().toString(), password.getText().toString());
            //将检验事件回调给presenter,让他通知model进行检验
            presenter.checkLogin(user);
        }
    }
    

    Presenter层:

    接下来是重点了,我们的Presenter类。
    传递
    作为view和model的中间传达者。view告诉presenter需要检验了,然后presenter在告诉model,并把得到的user值给model,让model进行检验。
    申明presenter的接口类。

    public interface LoginPresenter {
        void checkLogin(User user);
    }
    

    接口实现类LoginPresenterImpl,我们在presenter的实例中,获取到view和model的实例,然后在里面对其进行信息传递。

    public class LoginPresenterImpl implements LoginPresenter,LoginModelListener{
        LoginView view;
        LoginModel model;
    
        public LoginPresenterImpl(LoginView loginView){
            //从Activity中获取到对view的引用
            this.view = loginView;
            //申明一个新的model
            model = new LoginModelImpl();
        }
    
        @Override
        public void checkLogin(User user) {
            //保证视图是存在的
            if (view == null){
                return;
            }
            //显示view中的dialog,然后对user信息进行验证
            view.showDialog();
            model.login(user,this);
        }
    }
    

    这样我们就实现了将view的事件,通过presenter传递给了model层,让他去处理这一次的检验事件,但是大家有没有发现,我们是将这个事件传递给了model,但是model在处理完了之后,他又怎么将得到的结果通知给presenter呢?因为我们要避免view和model直接接触。所以在这里,我们还需要一个listenter的接口类,让presenter继承这个接口,在传递给model的时候,携带接口一起传过去。然后model通过这个接口告诉presenter,presenter再去通知view。

    public interface LoginModelListener {
        void loginSuccess();
        void loginError();
    }
    
    public interface LoginModel {
        void login(User user, LoginModelListener listener);
    }
    
    public class LoginModelImpl implements LoginModel{
        @Override
        public void login(User user, final LoginModelListener listener) {
            final String name = user.getName();
            final String password = user.getPassword();
    
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    Boolean error =false;
                    if (TextUtils.isEmpty(name)){
                        error = true;
                        //输入错误
                        System.out.println("输入错误");
                        listener.loginError();
                    }
                    if (TextUtils.isEmpty(password)){
                        error = true;
                        //输入错误
                        System.out.println("输入错误");
                        listener.loginError();
                    }
                    if(!error){
                        //登录成功
                        System.out.println("登录成功");
                        listener.loginSuccess();
                    }
                }
            },2000);
        }
    }
    

    至此,我们就实现了一个简单的MVP的demo,是不是觉得Acitivity里面的逻辑很简单了,看着一下字就轻松了很多。

    三、总结

    那么我们现在结合刚才的案例。我们再来总结一下。

    因为我们要保证view和model直接不能直接通信,所有之间的交互,我们都要通过presenter这一个中间类来进行传递。persenter中拥有view和model的引用,然后,view中有事件产生时,将事件以及需要的参数传给presenter,presenter再交给model,待model处理完了之后,将反馈信息传给presenter,presenter再将返回结果告诉view,最后呈现给用户。

    流程图

    github代码

    相关文章

      网友评论

          本文标题:Android MVP的简单实现

          本文链接:https://www.haomeiwen.com/subject/djaebxtx.html