mvp_mvparms - CSDN
mvp 订阅
美国职业篮球联赛最有价值球员奖(National Basketball Association Most Valuable Player Award ,简称MVP)是一个自1955-1956赛季以来每年对美国职业篮球联赛(NBA)常规赛中全场表现最佳的球员所颁发的一个奖项。为纪念NBA首位总裁莫里斯·波多罗夫,于是将MVP奖杯命名为“莫里斯·波多罗夫杯“。 展开全文
美国职业篮球联赛最有价值球员奖(National Basketball Association Most Valuable Player Award ,简称MVP)是一个自1955-1956赛季以来每年对美国职业篮球联赛(NBA)常规赛中全场表现最佳的球员所颁发的一个奖项。为纪念NBA首位总裁莫里斯·波多罗夫,于是将MVP奖杯命名为“莫里斯·波多罗夫杯“。
信息
外文名
National Basketball Association Most Valuable Player Award
奖杯名称
莫里斯·波多罗夫杯
出    处
NBA
中文名
美国职业篮球联赛最有价值球员奖
开始时间
1955-56赛季
美国职业篮球联赛最有价值球员奖奖项信息
NBA常规赛结束后就会进行最有价值球员(MVP)的投票评选工作。直到1979-1980赛季,最初的MVP奖项都是由NBA球员投票评选出的。然而从1980-1981赛季开始,由美国和加拿大的体育记者和电视评论员投票决定MVP奖项的最终归属。每一位评委分别投票选出自己心目中最好的第一到第五位的球员。球员每获得一张第一位的选票将获得10分,第二位选票获得7分,第三位选票获得5分,第四位选票3分,第五位选票获得1分。从2010年开始,将有一张选票是由球迷通过网络投票评选出的,得票最多的球员将获得这张选票。 [1]  入选奈·史密斯篮球名人纪念堂的卡里姆·阿布杜尔-贾巴尔曾6次获得这一奖项。 [2]  比尔·拉塞尔和迈克尔·乔丹均5次获得该奖, [1]  而威尔特·张伯伦、勒布朗·詹姆斯则4次获得该奖。另外,名人堂球员摩西·马龙、拉里·伯德和埃尔文·约翰逊(“魔术师”约翰逊)都3次获得该奖;鲍勃·佩蒂特、卡尔·马龙、史蒂夫·纳什、蒂姆·邓肯、斯蒂芬·库里均2次斩获该奖项。 [1]  2014年NBA最有价值球员奖授予了凯文·杜兰特,他获得了125张第一名选票中的119张。 [3]  2016年斯蒂芬·库里成为NBA历史上首个全票当选MVP的球员。只有两位球员在新秀赛季就拿到了这个奖,分别是1959-1960赛季的威尔特·张伯伦,1968-1969赛季的韦斯·昂塞尔德。 [4]  获得该奖而非美国出生的球员有尼日利亚的哈基姆·奥拉朱旺 [5]  、美属维尔京群岛的蒂姆·邓肯、加拿大的史蒂夫·纳什 [6]  、德国的德克·诺维茨基、希腊的扬尼斯·安特托昆博。邓肯其实是美国公民,不过由于他并不是在美国的50个州或者华盛顿出生,所以他被看作是一名国际球员。比尔.拉塞尔,威尔特.张伯伦,拉里.伯德都曾连续三年获得MVP奖项。
收起全文
精华内容
参与话题
  • Android之浅谈Android中的MVP

    万次阅读 2018-10-17 18:01:53
    转载请标明出处: ...前言为什么使用MVP,网上有很多说法,最主要就是减轻了Activity的责任,相比于MVC中的Activity承担的责任太多,因此有必要讲讲MVPMVP入门在MVC框架中,View是可以直接读取Model模型中的数据

    转载请标明出处:
    http://blog.csdn.net/hai_qing_xu_kong/article/details/51745798
    本文出自:【顾林海的博客】

    个人开发的微信小程序,目前功能是书籍推荐,后续会完善一些新功能,希望大家多多支持!
    在这里插入图片描述

    前言

    为什么使用MVP,网上有很多说法,最主要就是减轻了Activity的责任,相比于MVC中的Activity承担的责任太多,因此有必要讲讲MVP。

    MVP入门

    在MVC框架中,View是可以直接读取Model模型中的数据的,Model模型数据发生改变是会通知View数据显示发生相应的改变。而在MVP中Model和View之间的没有任何联系,是两个完全独立的模块,当Model模型发生数据改变时,通过Presenter通知View视图发生相应的UI改变。因此,个人觉得:MVP才是正真的视图和模型完全分离,也就是Model模型进行业务数据处理和View视图显示没有任何关联。可以通过下图看出:

    以下是MVC的框架图:

    这里写图片描述

    以下是MVP的框架图:

    这里写图片描述

    有关MVP说明的文章现在网上一大堆,最近自己也在尝试使用MVP去构建应用,关于MVP三层的定义,可以看看下面相关资料:

    model

    数据加工处理厂

    model是整个应用或界面的数据加工处理厂,所谓数据加工厂就是对数据的获取,数据的解析,数据的存储,数据的分发,数据的增删改查等操作。意思就是凡是涉及到数据操作都是在model进行的,所以model不仅仅只是实体类的集合,同时还包含关于数据的各种处理操作。

    三种数据源

    数据的数据源有三种:内存,磁盘(文件或数据库等),网络。为了提升app的性能,有必要把经常访问的数据临时存入内存中;同时也为了提升app性能和为用户省流量省电,有必要把数据存入磁盘中;还有的数据是有必要从网络读取的。三个数据源不一定同时存在,比如不与网络交互的app,不存在网络数据源。所以凡是涉及到关于数据发生于三个数据源加工处理的操作的代码都要放在model中。

    model为上层提供的服务:

    model从黑盒的角度来看为上层(指依赖于model的层比如present)提供的服务无非就2种:model为上层提供数据,model处理上层传递的数据

    model为上层提供数据:

    上层会从model中去数据,那model会从三数据源中取数据,取的顺序是

    • 先内存,内存取到数据返回
    • 其次磁盘,磁盘取到数据,如有必要把数据存储在内存中,则需要进行存储,返回数据
    • 最后网络,网络取到数据,如有必要在磁盘或内存中存储,则进行存储,返回数据

    上面的取数据过程是最简单的情况,复杂些还会涉及到从内存或磁盘中取到的数据是否过期,过期的话就应该从网络获取。从网络取得数据后需要把内存或磁盘的数据更新。

    model处理上层传递的数据:

    model接收到上层传递的数据后,model会依次把数据扔给三个数据源去处理,有可能三个数据源都会处理数据,有可能只是其中一个处理,model会把处理的结果返回。

    所以model会把解析好的数据提供给上层,上层对于数据的来源完全是透明的,上层完全不需要关心数据到底是来自内存,还是磁盘甚至是网络。同理上层只需要的把数据扔给model,上层唯一做的事情就是愉快的等待处理结果。

    presenter

    presenter翻译成汉语的意思是主持人,提出者。从它的意思可以看出它有控制全场的作用。首先presenter是处于mvp的中间层,在view和model中起一个承上启下的作用。presenter会把view交给自己的命令进行一定的校验等操作交给model处理,会把model处理的结果交给view。

    presenter封装业务:
    presenter不仅起一个桥梁的作用,它还会把业务逻辑代码给包揽下来。这样就可以减轻Activity的负担了,让Activity全心全意做它的view工作。那估计就有朋友犯迷糊了,哪些代码属于业务逻辑呢?比如一些校验代码。或者可以这样想只要是不属于view和model的代码基本都可以放在presenter中。

    presenter负责刷新view:
    mvc或以前的关于view的写法一般都是这样,view在接收到数据后,自己来进行view的刷新或其他操作。但是mvp中presenter负责对view进行刷新,比如从model获取的数据,presenter会根据获取的数据成功与否来通知view应该是显示成功界面还是失败界面。这样就让Activity变的更轻了,变成了听别人指挥的傻白甜了。这时候的presenter就有点主持人,掌控者的味道了。

    presenter持有的线程:
    Android中view的操作需要在ui线程里执行,其他耗时操作需要在普通线程执行。presenter会持有这2种线程:ui线程,普通线程。刷新view时,它切换为ui线程进行刷新,从model取数据切换为普通线程。假如使用rxjava的话,就特别简单了关于线程切换的事情。

    view

    view层就很好理解了,就是用户直接看到的界面,mvp中的view是很省心的,比如更新view,接收数据。这些操作它都不需要操心,也不需要知道数据到底来自哪里,给我啥我显示啥就可以了。

    一个view可以同时拥有多个presenter,也可以只有一个presenter。

    Android中的Activity,Fragment在mvp中是作为view来使用的,这些Activity,Fragment的责任就小了,只关心界面相关的事情足矣。各种Adapter是放在view层的。

    案例展示

    既然清楚了MVP的一些概念,现在就可以创建一个项目,整个项目很简单,通过点击按钮获取天气信息并显示在界面上,这里面我们使用MVP来搭建整个项目,先从Mode开始到Presenter最后View的创建。(天气接口使用的是心知天气提供的SDK http://www.thinkpage.cn/doc#info )

    案例Model层

    代码展示:

    package weather.weatherproject.mode;
    
    import com.thinkpage.lib.api.TPCity;
    import com.thinkpage.lib.api.TPListeners;
    import com.thinkpage.lib.api.TPWeatherManager;
    import com.thinkpage.lib.api.TPWeatherNow;
    
    import weather.weatherproject.WeatherApplication;
    
    /**
     * 天气管理类
     * Created by glh on 2016-06-23.
     */
    public class WeatherManager {
    
        public static final WeatherManager instance = new WeatherManager();
    
        public interface WeatherListener{
            void onSuccess(TPWeatherNow response);
    
            void onFailed(String errString);
        }
    
    
        /**
         * 获取指定城市的实况天气。
         *
         * @param city
         * @param listener
         */
        public void getNowWeather(String city, final WeatherListener listener) {
    
            WeatherApplication.weatherManager.getWeatherNow(new TPCity(city), TPWeatherManager.TPWeatherReportLanguage.kSimplifiedChinese, TPWeatherManager.TPTemperatureUnit.kCelsius, new TPListeners.TPWeatherNowListener() {
                @Override
                public void onTPWeatherNowAvailable(TPWeatherNow tpWeatherNow, String s) {
                    if (tpWeatherNow != null) {
                        listener.onSuccess(tpWeatherNow);
                    } else {
                        listener.onFailed(s);
                    }
                }
            });
        }
    
    }
    
    

    我们知道Model层主要用于数据的输入和输出,因此这里创建了一个天气管理类,通过获取天气信息的方法获取数据,最后将数据传递给Presenter,Presenter只需要将城市名传递给Model层,而它只需监听获取信息的状态,因此内部创建了一个天气信息获取的监听接口,通过它使得Presenter进行信息获取的监听。

    案例Presenter层

    代码展示:

    package weather.weatherproject.presenter;
    
    /**
     * View的基础接口
     * Created by glh on 2016-06-23.
     */
    public interface IView {
        void initView();
    }
    
    package weather.weatherproject.presenter;
    
    /**
     *
     * Created by glh on 2016-06-23.
     */
    public interface IPresenter<V extends IView> {
        void onStop();
    
        void onResume();
    
        void onDestroy();
    
        void onPause();
    
        void onStart();
    
        void init(V view);
    }
    
    

    IView是一个基础接口,内部定义了一个initView方法,用于View的初始化。
    IPresenter也是一个基础接口,内部定义了一些 Activity或Fragment常用的生命周期方法,用于View与 Activity或Fragment的联动。

    package weather.weatherproject.presenter.weather;
    
    import weather.weatherproject.presenter.IPresenter;
    import weather.weatherproject.presenter.IView;
    import weather.weatherproject.view.bean.NowWeather;
    
    /**
     * 获取天气的约定类,用于组合IWeatherView和IWeatherPresenter
     * Created by glh on 2016-06-23.
     */
    public interface WeatherContract {
        interface IWeatherView extends IView {
            //获取指定城市的实况天气
            void showNowWeather(NowWeather result);
    
            void error(String error);
        }
    
        interface IWeatherPresenter extends IPresenter<IWeatherView> {
            void getWeather(String city);
        }
    }
    
    

    可以看到WeatherContract接口内部定义两个接口:
    1、IWeatherView接口,用于Presenter与View的数据传递。
    2、IWeatherPresenter接口,是连接Model与View的中间层。

    package weather.weatherproject.presenter.weather;
    
    import com.thinkpage.lib.api.TPWeatherNow;
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    import weather.weatherproject.mode.WeatherManager;
    import weather.weatherproject.presenter.bean.BeanUtil;
    
    /**
     * 获取天气的Presenter
     * Created by glh on 2016-06-23.
     */
    public class WeatherPresenter implements WeatherContract.IWeatherPresenter {
    
        private WeatherContract.IWeatherView mIWeatherView;
        private WeatherManager mWeatherManager = WeatherManager.instance;
        private ExecutorService mExecutorService = Executors.newFixedThreadPool(5);
    
        @Override
        public void init(WeatherContract.IWeatherView view) {
            this.mIWeatherView = view;
            mIWeatherView.initView();
        }
    
        @Override
        public void getWeather(final String city) {
            mExecutorService.execute(new Runnable() {
                @Override
                public void run() {
                    mWeatherManager.getNowWeather(city, new WeatherManager.WeatherListener() {
                        @Override
                        public void onSuccess(TPWeatherNow response) {
                            mIWeatherView.showNowWeather(BeanUtil.createNowWeather(response));
                        }
    
                        @Override
                        public void onFailed(String errString) {
                            mIWeatherView.error(errString);
                        }
                    });
                }
            });
        }
    
    
        @Override
        public void onStop() {
    
        }
    
        @Override
        public void onResume() {
    
        }
    
        @Override
        public void onDestroy() {
    
        }
    
        @Override
        public void onPause() {
    
        }
    
        @Override
        public void onStart() {
    
        }
    
    }
    
    

    WeatherPresenter主要做了以下几件事情:
    1、初始化了View。
    2、通过View传递过来的指令向Model层请求数据。
    3、监听Model层的状态,并将结果刷新到View上。
    请求数据属于耗时操作因此我们开辟了线程用与请求处理,最后通过UI线程刷新View。BeanUtil用于封装我们所需的数据。

    案例View层

    代码展示:

    package weather.weatherproject.view.base;
    
    import android.content.Intent;
    import android.os.Bundle;
    import android.support.annotation.Nullable;
    import android.support.v4.app.FragmentActivity;
    
    import java.util.HashSet;
    import java.util.Set;
    
    import weather.weatherproject.presenter.IPresenter;
    
    /**
     * 基类Activity,所有业务界面都继承此BaseActivity。
     * Created by glh on 2016-06-23.
     */
    public abstract class BaseActivity extends FragmentActivity {
        private Set<IPresenter> mAllPresenters = new HashSet<>(1);
    
        /**
         * 获取layout的id,具体由子类实现
         *
         * @return
         */
        protected abstract int getLayoutResId();
    
        /**
         * 需要子类来实现,获取子类的IPresenter,一个activity有可能有多个IPresenter
         */
        protected abstract IPresenter[] getPresenters();
    
        /**
         * 初始化presenters
         */
        protected abstract void onInitPresenters();
    
        /**
         * 事件监听
         */
        protected abstract void initEvent();
    
        /**
         * 从intent中解析数据,具体子类来实现
         *
         * @param argIntent
         */
        protected void parseArgumentsFromIntent(Intent argIntent) {
        }
    
        private void addPresenters() {
    
            IPresenter[] presenters = getPresenters();
            if (presenters != null) {
                for (int i = 0; i < presenters.length; i++) {
                    mAllPresenters.add(presenters[i]);
                }
            }
        }
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(getLayoutResId());
            if (getIntent() != null) {
                parseArgumentsFromIntent(getIntent());
            }
            addPresenters();
            onInitPresenters();
            initEvent();
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            //依次调用IPresenter的onResume方法
            for (IPresenter presenter : mAllPresenters) {
                if (presenter != null) {
                    presenter.onResume();
                }
            }
        }
    
        @Override
        protected void onStop() {
            super.onStop();
            //依次调用IPresenter的onStop方法
            for (IPresenter presenter : mAllPresenters) {
                if (presenter != null) {
                    presenter.onStop();
                }
            }
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            //依次调用IPresenter的onPause方法
            for (IPresenter presenter : mAllPresenters) {
                if (presenter != null) {
                    presenter.onPause();
                }
            }
        }
    
        @Override
        protected void onStart() {
            super.onStart();
            //依次调用IPresenter的onStart方法
            for (IPresenter presenter : mAllPresenters) {
                if (presenter != null) {
                    presenter.onStart();
                }
            }
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            //依次调用IPresenter的onDestroy方法
            for (IPresenter presenter : mAllPresenters) {
                if (presenter != null) {
                    presenter.onDestroy();
                }
            }
        }
    }
    

    BaseActivity只是做了一下封装,方便我们展示界面的使用,最后我们看看展示界面WeatherActivity:

    package weather.weatherproject.view.weather;
    
    import android.view.View;
    import android.widget.Button;
    import android.widget.TextView;
    import android.widget.Toast;
    
    import weather.weatherproject.R;
    import weather.weatherproject.presenter.IPresenter;
    import weather.weatherproject.presenter.weather.WeatherContract;
    import weather.weatherproject.presenter.weather.WeatherPresenter;
    import weather.weatherproject.view.base.BaseActivity;
    import weather.weatherproject.view.bean.NowWeather;
    
    /**
     * 天气界面
     * Created by glh on 2016-06-23.
     */
    public class WeatherActivity extends BaseActivity implements WeatherContract.IWeatherView {
    
        private WeatherPresenter mWeatherPresenter = new WeatherPresenter();
    
        private TextView tv_show;
        private Button btn_now_weather;
    
        @Override
        protected int getLayoutResId() {
            return R.layout.activity_main;
        }
    
        @Override
        protected IPresenter[] getPresenters() {
            return new IPresenter[]{mWeatherPresenter};
        }
    
        @Override
        protected void onInitPresenters() {
            mWeatherPresenter.init(this);
        }
    
        @Override
        protected void initEvent() {
            btn_now_weather.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(WeatherActivity.this, "onclick", Toast.LENGTH_SHORT).show();
                    mWeatherPresenter.getWeather("shanghai");
                }
            });
        }
    
        @Override
        public void showNowWeather(NowWeather result) {
            tv_show.setText(result.toString());
        }
    
        @Override
        public void error(String error) {
            tv_show.setText(error);
        }
    
        @Override
        public void initView() {
            tv_show = (TextView) findViewById(R.id.tv_show);
            btn_now_weather = (Button) findViewById(R.id.btn_now_weather);
        }
    }
    

    最后可以看到我们的Activity非常的简洁,到了这里我们的项目已经搭建完成,这样做有以下好处:
    1、学习过设计模式的人都知道,这样做基本符合了单一职责原则。
    2、符合单一职责原则后,导致类与类组织更清晰。
    3、View层与Model层交互需要通过Presenter层进行,这样v与m层级间的耦合性降低。
    4、通过这种分层处理,每一层的测试也相对简单,维护性更高。

    项目地址

    MVPDemo请点击这里

    展开全文
  • MVP详细解析以及使用方法

    千次阅读 多人点赞 2019-02-16 09:30:54
    需要结合开源项目理解MVP并逐步学会使用,本开源项目正在逐步完善中MVP(Module View Controller)是MVC的演进版本,所以首先介绍一下MVC(Module View Presenter)MVCMVC 是一种框架模式而非设计模式。框架:用来对...

    github地址:https://github.com/libin7278/MPV-example
    需要结合开源项目理解MVP并逐步学会使用,本开源项目正在逐步完善中
    ####MVP(Module View Controller)是MVC的演进版本,所以首先介绍一下MVC(Module View Presenter)

    #MVC
    ###MVC 是一种框架模式而非设计模式。
    框架:用来对软件设计进行分工。
    设计模式:小技巧,对具体问题提出解决方案,太高代码复用率,降低耦合度。
    ###MVC在Android中的实现
    View层一般采用XMl文件进行界面的描述;
    Module则对应本地数据文件或者网络获取的数据体;
    Controller部分则由Activity承担;
    这个框架并非我们自己完成的,而是由framework给我们搭建好并提供给我们。
    #MVP
    解除了View和Module的耦合,同时又带来了良好的可扩展性,可测试性。
    使用MVP的好处:UI可能随时改变,如果业务逻辑耦合在View中,UI修改会导致我们重新抽离View中的业务逻辑。MVP刚好帮我们完成了逻辑抽离。
    ###区别
    (1)MVC中是允许Model和View进行交互的,而MVP中很明显,Model与View之间的交互由Presenter完成。
    (2)还有一点就是Presenter与View之间的交互是通过接口的。
    首先看一下实现了MVP的Activity出来的效果,这是一个最简单的用户名登录

    MVC特点
    1.用户可以向View发送指令,再由View直接要求Modle改变状态
    2.用户可以直接向Controller发送指令,再由Controller发送View
    3.Controller起到事路由的作用,同时业务逻辑都部署在Controller
    这里写图片描述

    MVVM特点
    View和Model进行双向绑定,两者之间有一方发生变化则会反映到另一方上。ViewModle要做的只是业务逻辑处理,以及修改View或者Modle的状态。
    这里写图片描述

    MVP特点
    View更新通过Presenter,View和Modle不直接联系
    这里写图片描述

    package com.mvp.libin.mvp_example;
    
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.ProgressBar;
    import android.widget.Toast;
    
    import com.mvp.libin.mvp_example.base.MVPBaseActivity;
    import com.mvp.libin.mvp_example.bean.User;
    import com.mvp.libin.mvp_example.presenter.UserLoginPresenterB;
    import com.mvp.libin.mvp_example.view.IViewUserLogin;
    
    /**
     * Created by libin on 16/11/9.
     */
    
    public class ActivityBUserLogin extends MVPBaseActivity<IViewUserLogin,UserLoginPresenterB>implements IViewUserLogin {
        private EditText et_usernam,et_userpassword;
        private ProgressBar pb;
        private Button btn_login,btn_clear;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_login);
    
            findViewById();
    
            //登录
            btn_login.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mPresenter.login();
                }
            });
    
            //清除
            btn_clear.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mPresenter.clear();
                }
            });
    
        }
    
        @Override
        protected UserLoginPresenterB createPresenter() {
            return new UserLoginPresenterB(this);
        }
    
        private void findViewById() {
            et_userpassword = (EditText) findViewById(R.id.et_userpassword);
            et_usernam = (EditText) findViewById(R.id.et_usernam);
    
            btn_login = (Button) findViewById(R.id.btn_login);
            btn_clear = (Button) findViewById(R.id.btn_clear);
    
            pb = (ProgressBar) findViewById(R.id.pb);
        }
    
        @Override
        public String getUserName() {
            return et_usernam.getText().toString();
        }
    
        @Override
        public String getPassword() {
            return et_userpassword.getText().toString();
        }
    
        @Override
        public void clearUserName() {
            et_usernam.setText("");
        }
    
        @Override
        public void clearPassword() {
            et_userpassword.setText("");
        }
    
        @Override
        public void showLoading() {
            pb.setVisibility(View.VISIBLE);
        }
    
        @Override
        public void hideLoading() {
            pb.setVisibility(View.INVISIBLE);
        }
    
        @Override
        public void toMainActivity(User user) {
            Toast.makeText(this, user.getUsername() + " login success , to MainActivity", Toast.LENGTH_SHORT).show();
        }
    
    
        @Override
        public void showFailedError() {
            Toast.makeText(this, " login failed ", Toast.LENGTH_SHORT).show();
        }
    }
    
    

    首先考虑一下View 我们这个登录都需要啥?
    然后定义出所有需要的方法

    package com.mvp.libin.mvp_example.view;
    
    import com.mvp.libin.mvp_example.bean.User;
    
    /**
     * Created by libin on 16/11/8.
     */
    
    public interface IViewUserLogin {
        String getUserName();
    
        String getPassword();
    
        void clearUserName();
    
        void clearPassword();
    
        void showLoading();
    
        void hideLoading();
    
        void toMainActivity(User user);
    
        void showFailedError();
    }
    
    

    实现模型所需要的接口

    public interface IUserModel {
        public void login(String username, String password, OnLoginListener loginListener);
    }
    

    实现模型所需要的接口

    public interface OnLoginListener {
        void loginSuccess(User user);
    
        void loginFailed();
    }
    

    具体的业务在module完成

    public class UserModel implements IUserModel {
        @Override
        public void login(final String username, final String password, final OnLoginListener loginListener) {
            //模拟子线程耗时操作
            new Thread()
            {
                @Override
                public void run()
                {
                    try
                    {
                        Thread.sleep(2000);
                    } catch (InterruptedException e)
                    {
                        e.printStackTrace();
                    }
                    //模拟登录成功
                    if ("123".equals(username) && "123".equals(password))
                    {
                        User user = new User();
                        user.setUsername(username);
                        user.setPassword(password);
                        loginListener.loginSuccess(user);
                    } else
                    {
                        loginListener.loginFailed();
                    }
                }
            }.start();
        }
    }
    

    将View和modle关联到一起

    public class UserLoginPresenterB extends BasePresenter<IViewUserLogin> {
        private IUserModel userBiz;
        private IViewUserLogin userLoginView;
        private Handler mHandler = new Handler();
    
        public UserLoginPresenterB(IViewUserLogin userLoginView)
        {
            this.userLoginView = userLoginView;
            this.userBiz = new UserModel();
        }
    
        public void login()
        {
            userLoginView.showLoading();
            userBiz.login(userLoginView.getUserName(), userLoginView.getPassword(), new OnLoginListener()
            {
                @Override
                public void loginSuccess(final User user)
                {
                    //需要在UI线程执行
                    mHandler.post(new Runnable()
                    {
                        @Override
                        public void run()
                        {
                            userLoginView.toMainActivity(user);
                            userLoginView.hideLoading();
                        }
                    });
    
                }
    
                @Override
                public void loginFailed()
                {
                    //需要在UI线程执行
                    mHandler.post(new Runnable()
                    {
                        @Override
                        public void run()
                        {
                            userLoginView.showFailedError();
                            userLoginView.hideLoading();
                        }
                    });
    
                }
            });
        }
    
        public void clear()
        {
            userLoginView.clearUserName();
            userLoginView.clearPassword();
        }
    }
    

    接下来我们来看一下基类的实现,之所以要用弱引用,是因为Presenter经常执行一些耗时的操作,而presenter持有Activity的强引用,如果在请求结束之前Activity被销毁,网络请求还没有返回,导致presenter一直持有activity的对象,使得activity对象无法被回收,此时发生内存泄漏。

    package com.mvp.libin.mvp_example.base;
    
    import java.lang.ref.Reference;
    import java.lang.ref.WeakReference;
    
    /**
     * Created by libin on 16/11/8.
     */
    
    public class BasePresenter<T> {
        protected Reference<T> mViewRef;  //View接口类型的弱引用
    
        /**
         * 建立关联
         * @param view
         */
        public void attachView(T view){
            mViewRef = new WeakReference<T>(view);
        }
    
        /**
         * 获取View
         * @return
         */
        protected T getView(){
            return mViewRef.get();
        }
    
        /**
         * 判断是否与View建立关联
         * @return
         */
        public boolean isViewAttach(){
            return mViewRef != null && mViewRef.get() != null;
        }
    
        /**
         * 解除关联
         */
        public void detechView(){
            if(mViewRef != null){
                mViewRef.clear();
                mViewRef = null;
            }
        }
    }
    
    
    public abstract class MVPBaseActivity<V,T extends BasePresenter<V>> extends Activity{
        protected T mPresenter;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            mPresenter = createPresenter(); //创建Presenter
    
            mPresenter.attachView((V) this); //View与Presenter建立关联
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            mPresenter.detechView();  //解除关联
        }
    
        protected abstract T createPresenter();
    }
    

    扫码关注公众号“伟大程序猿的诞生“,更多干货新鲜文章等着你~

    公众号回复“资料获取”,获取更多干货哦~

    有问题添加本人微信号“fenghuokeji996” 或扫描博客导航栏本人二维码

    展开全文
  • MVP模式从入门到精通

    万次阅读 多人点赞 2019-03-12 16:09:53
    首先附上自己写的一个MVP的demo,这是一个很标准的MVP,Github地址如下: https://github.com/SilasGao/MVPDemo 首先MVP 是从经典的MVC架构演变而来,那我们是不是要先说下何为MVC模式? 系统C/S(Client/...

    首先附上自己写的一个MVP的demo,这是一个很标准的MVP,Github地址如下:

    https://github.com/SilasGao/MVPDemo

     

    首先MVP 是从经典的MVC架构演变而来,那我们是不是要先说下何为MVC模式?

     

    系统C/S(Client/Server)三层架构模型:

    1)视图层(View):一般采用XML文件对应用的界面进行描述,使用的时候可以直接引入,极为方便,可以的大大缩短开发时间,也可以使用JavaScript+HTML等的方式作为View层,当然这里需要进行Java和JavaScript之间的通信,幸运的是,Android提供了非常方便的通信实现。业务逻辑层(BLL):它的关注点主要集中在业务规则的制定、业务流程的实现等与业务需求有关的系统设计,也即是说它是与系统所应对的领域(Domain)逻辑有关,很多时候,也将业务逻辑层称为领域层。

    2)控制层(Controller):Android的控制层的重任通常落在了众多的Acitvity的肩上,这句话也就暗含了不要在Acitivity中写代码,要通过Activity交割Model业务逻辑层处理。

    3)模型层(Model):对数据库的操作、以及其他和数据有关的的操作都应该在Model里面处理,当然对业务计算等操作也是必须放在的该层的。就是应用程序中二进制的数据。

       三层结构架构三层间的交互及作用如下图所示:

     

    传统的MVC模式是很不错,我们也很熟悉,毕竟用了这么多年了。(突然想到之前去一家公司面试他问个HelloWord的Android项目是不是MVC,我说不是,他说回答错误,阿西吧!)

    在Android项目上你会发现Activity的责任太重,什么东西都要放在Activity中,最终导致了Activity太过臃肿。虽然能抽的都抽出来了,但是会发现代码还是很多,试想下上千行代码还没有注释,能不晕?即使是自己写的,过些日子去看也有些晕晕的吧?

    尤其代码敲完,一个月后需求又改了,从600、700行代码中找到要修改的地方也是要一点功夫的。

    为了给Activity减轻压力,这时候MVP出现了!

     

    MVP有什么好处,为什么要用MVP呢?

    网上搜下一大堆MVP的各种好处,本人总结下主要有以下几点:

     

    • 代码解耦
    • 结构清晰
    • 可复用
    • 扩展性高
    • 方便进行单元测试

    在MVP中View并不直接使用Model,它们之间的通信是通过Presenter (MVC中的Controller)来进行的,所有的交互都发生在Presenter内部,而在MVC中View会从直接Model中读取数据而不是通过 Controller。

    在MVP里,Presenter完全把Model和View进行了分离,主要的程序逻辑在Presenter里实现。而且,Presenter与具体的View是没有直接关联的,而是通过接口进行交互,从而使得在变更View时候可以保持Presenter的不变,可以多次复用。

    在MVP里,应用程序的逻辑主要在Presenter来实现,其中的View是很薄的一层,只应该有简单的Set/Get的方法,用户输入和设置界面显示的内容,除此就不应该有更多的内容,绝不容许直接访问Model。

    MVP主要解决就是把逻辑层抽出来成P层,要是遇到需求逻辑上的更改就可以只需要修改P层了或者遇到逻辑上的大改我们可以直接重写一个P也可以,很多开发人员把所有的东西都写在了Activity/Fragment里面这样一来遇到频繁改需求或者逻辑越来越复杂的时候,Activity /Fragment里面就会出现过多的混杂逻辑导致出错,所以MVP模式对于APP来对控制逻辑和UI的解耦来说是一个不错的选择。

     

     

    上面说逻辑是在Presenter中处理的,假设这是一个登陆界面,如要输入账号密码,那么对账号密码的是否为空判断以及正则表达式判断等也要放在Presenter中,毕竟这些都是逻辑。

    然后判断都成功的话(下面的操作都是在Presenter中进行的),先调用view层的方法,让ProgressDialog显示出来,然后调用model层的网络请求,结果的话在presenter中回调。在回调里面分别做ProgressDialog消失的处理,然后成功的话调用view层的方法,进入主界面。失败的话调用view层的方法,提示失败Toast之类的。

    这就是最简单的一个流程了。

     

     

    MVP是什么?怎么实现?

     

    下图是本人Demo中的代码,就一个页面而已,然而一个页面竟然有这么多的类,11个,我勒个去,吓死宝宝了,这么多的类,说实话一个类就能解决了。不慌,下面让我们仔细分析为什么这么多类

    首先介绍下每个类是干嘛的:

    • BuyBooActivity是我们的Activity
    • BaseActivity是Activity的基类
    • BasePresenter是Presenter的基类
    • BuyBookBean是我们的bean,也就是传说中的实体类,几个成员变量,自动生成一堆get、set方法的那个类
    • IBuyBookView也就是BuyBooActivity的接口
    • BuyBookPresenter也就是这个Actvity的Presenter
    • IBuyBookPresenter是BuyBookPresenter的接口
    • BuyBookModel是这个Activity的数据层
    • IBuyBookModel是BuyBookModel的接口
    • BuyBookAdapter是BuyBooActivity里面ListView的适配器
    • ValueCallBack,是一个通用的回调接口

    这里接口都以I开头,每个model,presenter,还有Activity的view,都对应着一个接口,有些人可能会问了,干嘛写接口,一下多了这么多类,看的都懵逼了(比如以前有一个同事,他一直说项目用MVP,但是他不知道什么是MVP,直接把数据层写在了P中,估计是他以为bean才是model吧。我也不跟他说,毕竟人家工资比较高。说道这里突然想起了他以前的MVVM模式,第一个M是bean,他说这是model,第二个M以及一个V他说这是viewmodel,结果放的是所有的网络请求,最后一个V他放的是Aciivty和Fragment了。好了笑话说到这里,继续我们的主题)

     

    为什么写接口?

    问这个问题的童鞋应该去复习设计模式的六大基本原则了,我们要控制项目而不是项目控制我们,我们要进行的是面向接口的编程,用抽象(或者接口)搭建框架,用实现扩展细节。当然接口也不能滥用,都要看具体情况,这里本人是按照最高标准来写的。

     

    Google官方MVP示例项目是把上面的IBuyBookPresenter以及IBuyBookView这2个接口放到了IBuyBookContract这个协议类中,实际上是一样的,这就看个人喜好了,各有各的优缺点。比如把本栗子的代码改成有协议类的这种就如下代码所示,看到了吧,其实是一样的。

    public interface IBuyBookContract
    {
        interface IBuyBookView
        {
            void showToast(String msg);
    
            void refreshAdapter();
    
            void onEmpty();
        }
    
        interface IBuyBookModel
        {
    
            List<BuyBookBean> getAdapterData();
        }
    }

     

    M(Model)

    数据层,和MVC中的M一样,用来放数据的处理(比如网络请求,缓存等)。

     

    V(View)

    负责UI具体实现展现。比如Presenter派发过来一个动作是showDialog显示进度命令,那么我们这个View就负责实现具体UI。

     

    P(Presenter)

    负责处理业务逻辑代码,处理Model数据,然后将处理完的数据分发到View层。

     

     

    下面开始贴代码讲解

     

    先来讲View IBuyBookView

    这里主要是包含了Activity的一系列关于UI操作,然后用我们的Activity是实现,这样Presenter就可以调用了。

     

    public interface IBuyBookView {
        /**
         * 提示toast
         */
        void showToast(String msg);
    
        /**
         * 刷新adapter
         */
        void refreshAdapter();
    
        void onEmpty();
    }
    


    接下来讲Model IBuyBookModel BuyBookModel

     

    主要是写了几个方法供BuyBookModel去实现

     

    public interface IBuyBookModel {
        /**
         * 获取模拟数据
         */
        void getTestData(ValueCallBack<List<BuyBookBean>> callBack);
    
    
        /**
         * 返回本地adapter数据
         * @return
         */
        List<BuyBookBean> getAdapterData();
    }

     

    这里实现了IBuyBookModel,然后模拟了下网络请求,用随机来模拟请求成功与失败,所以如果有童鞋下载Demo发现进去怎么空白一片,那么请退出来多近几次,本人曾连续5次进去都是空白的,这运气也太背了吧。

     

    public class BuyBookModel implements IBuyBookModel {
        private List<BuyBookBean> listData;
    
    
        public BuyBookModel() {
            this.listData = new ArrayList<>();
        }
    
        @Override
        public void getTestData(final ValueCallBack<List<BuyBookBean>> callBack) {
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    List<BuyBookBean> list = new ArrayList<>();
                    list.add(new BuyBookBean("赵云", 1, "09-27 09:11"));
                    list.add(new BuyBookBean("赵云、隔壁老王、小王、典韦、貂蝉、林芳、曹操、刘备、关羽、黄忠、张飞、诸葛孔明", 10, "09-27 09:11"));
                    list.add(new BuyBookBean("黄忠、孙权、大乔", 50, "09-27 09:11"));
                    list.add(new BuyBookBean("大乔、小乔、貂蝉、孙尚香", 300, "09-27 09:11"));
    
                    Random rd = new Random();
                    int N = rd.nextInt(10);
                    if (N > 5) {
                        callBack.onSuccess(list);
                    } else {
                        callBack.onFail("拒绝请求");
                    }
                }
            }, 1000);
        }
    
    
        @Override
        public List<BuyBookBean> getAdapterData() {
            return listData;
        }
    }
    

     

    这里贴上楼上那个回调接口,这里用了泛型,为什么呢?为了多多复用。

     

    public interface ValueCallBack<T> {
        void onSuccess(T t);
    
        void onFail(String code);
    }
    


    接下来讲Presenter BasePresenter IBuyBookPresenterBuyBookPresenter

    这个是所有Presenter的基类,里面有个initData()方法,基本每个Presenter都要处理网络请求吧,所以我就弄了这么一个基类,至于为什么是抽象的而不是接口,这是因为抽象方便点吧,如果我们往抽象类中添加新的方法(该方法不是抽象的),可以给他提供默认的实现,而且不要修改现有的代码,但是如果是接口的话,就要修改现有的代码了。指不定我们以后要往这里加什么呢。

    这里为什么用了个泛型?为了让人一看这个Presenter就知道这对应着哪个Activity,实际上这可以不加的,但是我觉得加上去更好。便于后来人也便于自己以后再来修改这个类。

     

    public abstract class BasePresenter<T extends BaseActivity> {
    
        abstract void initData();
    }
    

     

     

     

    这里主要写了个方法,以供BuyBookPresenter实现

     

    public interface IBuyBookPresenter {
    
        List<BuyBookBean> getAdapterData();
    }
    

     

    这里首先实现现了IBuyBookPresenter继承了BasePresenter,然后重写一些方法。这里的构造方法是重点,在构造方法中,我们需要传入一个IBookView,实际上我们的Activity已经实现IBookView了,所以这里实际上传的是具体的Activity,也就是this就行了。然后model我们可以直接new出来用,这里就new了。

    在initData中我们是进行了具体的网络请求,网络请求我们是不是要弹一个Dialog出来,直接在这mView.loading();调用就行了。然后请求成功onSuccess()里面让Dialog消失,提醒适配器刷新。失败的话onFail()里面提示Dialog消失,然后ListView设置失败页面什么的。

     

    public class BuyBookPresenter extends BasePresenter<BuyBookActivity> implements IBuyBookPresenter {
    
        private IBuyBookView  mView;
        private IBuyBookModel mModel;
    
        public BuyBookPresenter(IBuyBookView iBuyBookView) {
            this.mView = iBuyBookView;
            this.mModel = new BuyBookModel();
        }
    
    
        @Override
        public List<BuyBookBean> getAdapterData() {
            return mModel.getAdapterData();
        }
    
        @Override
        public void initData() {
            //在这里弹出loading
            mModel.getTestData(new ValueCallBack<List<BuyBookBean>>() {
                @Override
                public void onSuccess(List<BuyBookBean> buyBookBeen) {
                    //在这里取消loading
                    //简单数据操作可以在presenter里完成
                    mModel.getAdapterData().addAll(buyBookBeen);
                    mView.refreshAdapter();
                }
    
                @Override
                public void onFail(String code) {
                    //在这里取消loading
                    mView.showToast(code);
                    mView.onEmpty();
                }
            });
        }
    }


    接下来讲我们的Activity BuyBookActivity BaseActivity

    这是我们Acticity的基类,可以看到这里有个泛型,注意了,前方高能。这个泛型还必须继承BasePresenter,这个首先为了让人一看到这个Activity就知道对应着那个Presenter;其次最重要的就是为了下面那个成员变量basepresenter,我们写一个抽象的方法要求返回泛型T,而这个泛型T又继承了BasePresenter,那么我们就得到了具体Presenter的成员变量,可以直接用这个成员变量来调用Presenter中的方法了。

     

    public abstract class BaseActivity<T extends BasePresenter> extends Activity {
        
        protected T basepresenter;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(getLayout());
            initView();
            basepresenter = initPresent();
            onPrepare();
        }
    
        abstract T initPresent();
    
        abstract int getLayout();
    
        abstract void initView();
    
        abstract void onPrepare();
    }

    这个就是最终具体的Activity了,可以看到这里都没什么逻辑,基本都是一些重写的方法。

     

    public class BuyBookActivity extends BaseActivity<BuyBookPresenter> implements IBuyBookView
    {
    
        private ListView mListView;
        private BuyBookAdapter mAdapter;
    
        @Override
        BuyBookPresenter initPresent()
        {
            return new BuyBookPresenter(this);
        }
    
        @Override
        int getLayout()
        {
            return R.layout.activity_main;
        }
    
        @Override
        void initView()
        {
            mListView = (ListView) findViewById(R.id.listview);
        }
    
        @Override
        void onPrepare()
        {
            mAdapter = new BuyBookAdapter(this, basepresenter.getAdapterData());
            mListView.setAdapter(mAdapter);
            basepresenter.initData();
        }
    
        @Override
        public void showToast(String msg)
        {
            Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
        }
    
        @Override
        public void refreshAdapter()
        {
            mAdapter.notifyDataSetChanged();
        }
    
        public void onEmpty()
        {
            mListView.setEmptyView(null);
        }
    }

     

     

     

     

     

    最后虽然MVP模式有许多好处,但是有一个致命的缺点就是类太多,本来一个类最多变成了7个类,最少变成6个类(使用Contract协议类)。所以并不是所有的页面都要用MVP模式的,很简单的页面就没必要了,浪费时间是不是。

     

    为什么MVP模式利于单元测试?

     

     

    Presenter将逻辑和UI分开了,里面没有Android代码,都是纯纯的java代码。我们可以直接对Presenter写Junit测试

     

     

     

    最后:这个MVP模式是非常基础了,只是给大家提供一下这个思路。

    因为博客平时不是经常上,所以有问题需要及时回答的大佬们可以扫下这个。

    展开全文
  • 浅谈 MVP in Android

    万次阅读 多人点赞 2015-06-23 09:39:04
    对于MVP(Model View Presenter),大多数人都能说出一二:“MVC的演化版本”,“让Model和View完全解耦”等等。本篇博文仅是为了做下记录,提出一些自己的看法,和帮助大家如何针对一个Activity页面去编写针对MVP...

    转载请标明出处:
    http://blog.csdn.net/lmj623565791/article/details/46596109
    本文出自:【张鸿洋的博客】

    一、概述

    对于MVP(Model View Presenter),大多数人都能说出一二:“MVC的演化版本”,“让Model和View完全解耦”等等。本篇博文仅是为了做下记录,提出一些自己的看法,和帮助大家如何针对一个Activity页面去编写针对MVP风格的代码。

    对于MVP,我的内心有一个问题:

    为何这个模式出来后,就能被广大的Android的程序员接受呢?

    问了些程序员,他们对于MVP的普遍的认识是:“代码很清晰,不过增加了很多类”。我在第一次看到MVP的时候,看了一个demo,看完以后觉得非常nice(但是回过头来,自己想个例子写,就头疼写不出来,当然这在后文会说)。nice的原因还是因为,这个模式的确让代码的清晰度有了很大的提升。

    那么,提升一般都是对比出来的,回顾下,没有应用MVP的代码结构。很多人说明显是MVC么:

    • View:对应于布局文件
    • Model:业务逻辑和实体模型
    • Controllor:对应于Activity

    看起来的确像那么回事,但是细细的想想这个View对应于布局文件,其实能做的事情特别少,实际上关于该布局文件中的数据绑定的操作,事件处理的代码都在Activity中,造成了Activity既像View又像Controller(当然了Data-Binder的出现,可能会让View更像View吧)。这可能也就是为何,在该文中有一句这样的话:

    Most of the modern Android applications just use View-Model architecture,everything is connected with Activity.

    而当将架构改为MVP以后,Presenter的出现,将Actvity视为View层,Presenter负责完成View层与Model层的交互。现在是这样的:

    • View 对应于Activity,负责View的绘制以及与用户交互
    • Model 依然是业务逻辑和实体模型
    • Presenter 负责完成View于Model间的交互

    ok,先简单了解下,文中会有例子到时候可以直观的感受下。

    小总结下,也就是说,之所以让人觉得耳目一新,是因为这次的跳跃是从并不标准的MVCMVP的一个转变,减少了Activity的职责,简化了Activity中的代码,将复杂的逻辑代码提取到了Presenter中进行处理。与之对应的好处就是,耦合度更低,更方便的进行测试。借用两张图(出自:该文),代表上述的转变:

    20150622212835554

    转变为:

    20150622212856011

    二、MVP 与 MVC 区别

    ok,上面说了一堆理论,下面我们还是需要看一看MVC与MVP的一个区别,请看下图(来自:本文):

    20150622212916054

    其实最明显的区别就是,MVC中是允许Model和View进行交互的,而MVP中很明显,Model与View之间的交互由Presenter完成。还有一点就是Presenter与View之间的交互是通过接口的(代码中会体现)。

    还有一堆概念性的东西,以及优点就略了,有兴趣自行百度。下面还是通过一些简单的需求来展示如何编写MVP的demo。

    三、Simple Login Demo

    效果图:

    20150622212940112

    看到这样的效果,先看下完工后的项目结构:

    20150622213003064

    ok,接下来开始一步一步的编写思路。

    (一)Model

    首先实体类User不用考虑这个肯定有,其次从效果图可以看到至少有一个业务方法login(),这两点没什么难度,我们首先完成:

    package com.zhy.blogcodes.mvp.bean;
    
    /**
     * Created by zhy on 15/6/18.
     */
    public class User
    {
        private String username ;
        private String password ;
    
        public String getUsername()
        {
            return username;
        }
    
        public void setUsername(String username)
        {
            this.username = username;
        }
    
        public String getPassword()
        {
            return password;
        }
    
        public void setPassword(String password)
        {
            this.password = password;
        }
    }
    
    
    package com.zhy.blogcodes.mvp.biz;
    
    /**
     * Created by zhy on 15/6/19.
     */
    public interface IUserBiz
    {
        public void login(String username, String password, OnLoginListener loginListener);
    }
    
    
    
    package com.zhy.blogcodes.mvp.biz;
    
    import com.zhy.blogcodes.mvp.bean.User;
    
    /**
     * Created by zhy on 15/6/19.
     */
    public class UserBiz implements IUserBiz
    {
    
        @Override
        public void login(final String username, final String password, final OnLoginListener loginListener)
        {
            //模拟子线程耗时操作
            new Thread()
            {
                @Override
                public void run()
                {
                    try
                    {
                        Thread.sleep(2000);
                    } catch (InterruptedException e)
                    {
                        e.printStackTrace();
                    }
                    //模拟登录成功
                    if ("zhy".equals(username) && "123".equals(password))
                    {
                        User user = new User();
                        user.setUsername(username);
                        user.setPassword(password);
                        loginListener.loginSuccess(user);
                    } else
                    {
                        loginListener.loginFailed();
                    }
                }
            }.start();
        }
    }
    
    
    package com.zhy.blogcodes.mvp.biz;
    
    import com.zhy.blogcodes.mvp.bean.User;
    
    /**
     * Created by zhy on 15/6/19.
     */
    public interface OnLoginListener
    {
        void loginSuccess(User user);
    
        void loginFailed();
    }
    
    

    实体类不用说,至于业务类,我们抽取了一个接口,一个实现类这也很常见~~login方法,一般肯定是连接服务器的,是个耗时操作,所以我们开辟了子线程,Thread.sleep(2000)模拟了耗时,由于是耗时操作,所以我们通过一个回调接口来通知登录的状态。

    其实这里还是比较好写的,因为和传统写法没区别。

    (二) View

    上面我们说过,Presenter与View交互是通过接口。所以我们这里需要定义一个ILoginView,难点就在于应该有哪些方法,我们看一眼效果图:

    可以看到我们有两个按钮,一个是login,一个是clear;

    login说明了要有用户名、密码,那么对应两个方法:

    
        String getUserName();
    
        String getPassword();

    再者login是个耗时操作,我们需要给用户一个友好的提示,一般就是操作ProgressBar,所以再两个:

        void showLoading();
    
        void hideLoading();

    login当然存在登录成功与失败的处理,我们主要看成功我们是跳转Activity,而失败可能是去给个提醒:

        void toMainActivity(User user);
    
        void showFailedError();

    ok,login这个方法我们分析完了~~还剩个clear那就简单了:

        void clearUserName();
    
        void clearPassword();

    综上,接口完整为:

    package com.zhy.blogcodes.mvp.view;
    
    import com.zhy.blogcodes.mvp.bean.User;
    
    /**
     * Created by zhy on 15/6/19.
     */
    public interface IUserLoginView
    {
        String getUserName();
    
        String getPassword();
    
        void clearUserName();
    
        void clearPassword();
    
        void showLoading();
    
        void hideLoading();
    
        void toMainActivity(User user);
    
        void showFailedError();
    
    }

    有了接口,实现就太好写了~~~

    总结下,对于View的接口,去观察功能上的操作,然后考虑:

    • 该操作需要什么?(getUserName, getPassword)
    • 该操作的结果,对应的反馈?(toMainActivity, showFailedError)
    • 该操作过程中对应的友好的交互?(showLoading, hideLoading)

    下面贴一下我们的View的实现类,哈,其实就是Activity,文章开始就说过,MVP中的View其实就是Activity。

    package com.zhy.blogcodes.mvp;
    
    import android.os.Bundle;
    import android.support.v7.app.ActionBarActivity;
    import android.view.View;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.ProgressBar;
    import android.widget.Toast;
    
    import com.zhy.blogcodes.R;
    import com.zhy.blogcodes.mvp.bean.User;
    import com.zhy.blogcodes.mvp.presenter.UserLoginPresenter;
    import com.zhy.blogcodes.mvp.view.IUserLoginView;
    
    public class UserLoginActivity extends ActionBarActivity implements IUserLoginView
    {
    
    
        private EditText mEtUsername, mEtPassword;
        private Button mBtnLogin, mBtnClear;
        private ProgressBar mPbLoading;
    
        private UserLoginPresenter mUserLoginPresenter = new UserLoginPresenter(this);
    
        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_user_login);
    
            initViews();
        }
    
        private void initViews()
        {
            mEtUsername = (EditText) findViewById(R.id.id_et_username);
            mEtPassword = (EditText) findViewById(R.id.id_et_password);
    
            mBtnClear = (Button) findViewById(R.id.id_btn_clear);
            mBtnLogin = (Button) findViewById(R.id.id_btn_login);
    
            mPbLoading = (ProgressBar) findViewById(R.id.id_pb_loading);
    
            mBtnLogin.setOnClickListener(new View.OnClickListener()
            {
                @Override
                public void onClick(View v)
                {
                    mUserLoginPresenter.login();
                }
            });
    
            mBtnClear.setOnClickListener(new View.OnClickListener()
            {
                @Override
                public void onClick(View v)
                {
                    mUserLoginPresenter.clear();
                }
            });
        }
    
    
        @Override
        public String getUserName()
        {
            return mEtUsername.getText().toString();
        }
    
        @Override
        public String getPassword()
        {
            return mEtPassword.getText().toString();
        }
    
        @Override
        public void clearUserName()
        {
            mEtUsername.setText("");
        }
    
        @Override
        public void clearPassword()
        {
            mEtPassword.setText("");
        }
    
        @Override
        public void showLoading()
        {
            mPbLoading.setVisibility(View.VISIBLE);
        }
    
        @Override
        public void hideLoading()
        {
            mPbLoading.setVisibility(View.GONE);
        }
    
        @Override
        public void toMainActivity(User user)
        {
            Toast.makeText(this, user.getUsername() +
                    " login success , to MainActivity", Toast.LENGTH_SHORT).show();
        }
    
        @Override
        public void showFailedError()
        {
            Toast.makeText(this,
                    "login failed", Toast.LENGTH_SHORT).show();
        }
    }

    对于在Activity中实现我们上述定义的接口,是一件很容易的事,毕竟接口引导我们去完成。

    最后看我们的Presenter。

    (三)Presenter

    Presenter是用作Model和View之间交互的桥梁,那么应该有什么方法呢?

    其实也是主要看该功能有什么操作,比如本例,两个操作:login和clear。

    package com.zhy.blogcodes.mvp.presenter;
    
    import android.os.Handler;
    
    import com.zhy.blogcodes.mvp.bean.User;
    import com.zhy.blogcodes.mvp.biz.IUserBiz;
    import com.zhy.blogcodes.mvp.biz.OnLoginListener;
    import com.zhy.blogcodes.mvp.biz.UserBiz;
    import com.zhy.blogcodes.mvp.view.IUserLoginView;
    
    
    /**
     * Created by zhy on 15/6/19.
     */
    public class UserLoginPresenter
    {
        private IUserBiz userBiz;
        private IUserLoginView userLoginView;
        private Handler mHandler = new Handler();
    
        public UserLoginPresenter(IUserLoginView userLoginView)
        {
            this.userLoginView = userLoginView;
            this.userBiz = new UserBiz();
        }
    
        public void login()
        {
            userLoginView.showLoading();
            userBiz.login(userLoginView.getUserName(), userLoginView.getPassword(), new OnLoginListener()
            {
                @Override
                public void loginSuccess(final User user)
                {
                    //需要在UI线程执行
                    mHandler.post(new Runnable()
                    {
                        @Override
                        public void run()
                        {
                            userLoginView.toMainActivity(user);
                            userLoginView.hideLoading();
                        }
                    });
    
                }
    
                @Override
                public void loginFailed()
                {
                    //需要在UI线程执行
                    mHandler.post(new Runnable()
                    {
                        @Override
                        public void run()
                        {
                            userLoginView.showFailedError();
                            userLoginView.hideLoading();
                        }
                    });
    
                }
            });
        }
    
        public void clear()
        {
            userLoginView.clearUserName();
            userLoginView.clearPassword();
        }
    
    
    
    }
    

    注意上述代码,我们的presenter完成二者的交互,那么肯定需要二者的实现类。大致就是从View中获取需要的参数,交给Model去执行业务方法,执行的过程中需要的反馈,以及结果,再让View进行做对应的显示。

    ok,拿到一个例子经过上述的分解基本就能完成。以上纯属个人见解,欢迎讨论和吐槽~ have a nice day ~。

    源码点击下载

    微信公众号:hongyangAndroid
    (欢迎关注,第一时间推送博文信息)
    1422600516_2905.jpg

    参考资料

    展开全文
  • 一个小例子彻底搞懂 MVP

    万次阅读 多人点赞 2018-06-28 13:22:01
    本文由玉刚说写作平台提供写作赞助 原作者:Zackratos 版权声明:本文版权归微信...MVP 是从经典的模式 MVC 演变而来,它们的基本思想有相通的地方:Controller/Presenter 负责逻辑的处理,Model 提供数据,V...
  • Android MVP模式 入门

    万次阅读 2019-08-05 16:57:05
    近些年来,Android架构模式有很多,我们比较熟知的有MVC,MVP以及MVVM,目前Android市场中使用最多的应该是MVP架构,虽然MVVM结合DataBing看似更加方便,但在一般公司中使用的还是比较少。其实模式这种东西就像我们...
  • MVP模式使用示例详解

    千次阅读 2018-11-08 00:06:57
    什么是MVP模式? &amp;amp;amp;nbsp;&amp;amp;amp;nbsp;&amp;amp;amp;nbsp;&amp;amp;amp;nbsp;&amp;amp;amp;nbsp;这个MVP可不是腾讯游戏《王者荣耀》中的MVP。我们今天要讨论的MVP其实同MVC...
  • MVC、MVP、MVVM,我到底该怎么选?

    万次阅读 多人点赞 2020-08-27 17:09:53
    本文由玉刚说写作平台提供写作赞助 原作者:AndroFarmer 版权声明:本文版权归微信...比如看了好多篇文章都搞不懂MVC到底是个啥本来想写个MVP写着写着就变成MVC了,到底Databing和MVVM之间有啥见不得人的关系...
  • MVC、MVP、MVVM三种区别及适用场合

    万次阅读 多人点赞 2017-10-30 15:43:45
    本文将详细阐述以下MVC、MVP、MVVM三种理念的定义及区别还有他们的适用场合。
  • MVPMVP“最有希望获得最佳MVP”之“最有希望获得最佳MVP”之“最有希望获得最佳MVP”之“最有希望获得最佳MVP”之“最佳MVP”之“最佳MVP”之“最佳MVP”之“最佳MVP”之“最佳MVP”之“最佳MVP”之“最佳MVP”...
  • MVP模式的优缺点

    千次阅读 2018-04-08 22:48:54
    MVP模式是MVC的一个演化版本,全称是Model view Presenter。MVP能够有效的降低View的复杂性,避免业务逻辑被塞进View中,使得View变成一个混乱的“大泥坑”。MVP模式会解除View与Model的耦合,同时又带来了良好的可...
  • 主页面 Presenter
  • Google官方MVP架构例子。源码见: https://github.com/googlesamples/android-architecture 官方给出了四种MVP架构模式:1、todo-mvpMVP基础架构2、todo-mvp-loaders:基于MVP基础架构,获取数据部分使用了...
  • MVP框架优缺点及解决办法

    千次阅读 2019-06-29 17:09:54
    最近在面试发现好多公司都会问到MVP框架搭建 , 所有今天在这里来探讨一下我们经常使用的MVP框架 文章分为以下三个部分 一 .MVP 的概念 二 .MVP 的优缺点 三 .MVP 解决存在的问题 一 MVP 的概念 ...
  • 谷歌官方MVP例子分析

    千次阅读 2017-06-08 13:59:40
    官方给出了四种MVP架构模式: 1、todo-mvpMVP基础架构 2、todo-mvp-loaders:基于MVP基础架构,获取数据部分使用了Loaders架构 3、todo-mvp-databinding:基于MVP基础架构,使用了数据绑定组件 4、todo-mvp-...
  • 网上找了一下mvp模式的资料看的大概懵懵懂懂。找的资源也有一些。现有些问题想请教: 比如我现在开发winform有三个步骤:设计form界面(这个由designer.cs文件完成);为界面控件的各个事件(其中包括初始化form数据...
  • 在“快”的前提下, 敏捷开发是知道“方向”验证“方法”, 最小可行产品是知道“方法”验证“方向”。
  • MVP是什么,不是什么

    千次阅读 2019-04-25 19:41:33
    MVP = Minimum Viable Product各种文章、书里,有很多定义,我来汇总一下。先发一组经典对比图。用文字来解释就是——对自己,是用于验证学习的工具能通...
  • C# MVP简单实例

    热门讨论 2020-07-19 23:31:54
    C# MVP简单实例 C# MVP简单实例 C# MVP简单实例 C# MVP简单实例
  • MVP(Minimum Viable Product,最小可行性产品) 在执行MVP的过程中通常会出现两个情况。 创业团队没有足够的设计资源和时间,做出来的前几个版本MVP通常用户体验非常差,这种情况下体验差有可能让用户放弃这款...
1 2 3 4 5 ... 20
收藏数 58,951
精华内容 23,580
关键字:

mvp