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奖项。
收起全文
精华内容
参与话题
问答
  • 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模式从入门到精通

    万次阅读 多人点赞 2016-10-27 15:24:48
    首先附上自己写的一个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模式是非常基础了,只是给大家提供一下这个思路。

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

    展开全文
  • MVC、MVP、MVVM三种区别及适用场合

    万次阅读 多人点赞 2017-10-30 13:34:38
    本文将详细阐述以下MVC、MVP、MVVM三种理念的定义及区别还有他们的适用场合。

    本文将详细阐述以下MVC、MVP、MVVM三种理念的定义及区别还有他们的适用场合。

    MVC

    MVC模式最初生根于服务器端的Web开发,后来渐渐能够胜任客户端Web开发,能够满足其复杂性和丰富性。

    这里写图片描述

    MVC是Model-View-Controller的缩写,它将应用程序划分为三个部分:

    • Model: 模型(用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法)

    • View: 视图(渲染页面)

    • Controller: 控制器(M和V之间的连接器,用于控制应用程序的流程,及页面的业务逻辑)

    MVC特点:

    MVC模式的特点在于实现关注点分离,即应用程序中的数据模型与业务和展示逻辑解耦。在客户端web开发中,就是将模型(M-数据、操作数据)、视图(V-显示数据的HTML元素)之间实现代码分离,松散耦合,使之成为一个更容易开发、维护和测试的客户端应用程序。

    1. View 传送指令到 Controller ;

    2. Controller 完成业务逻辑后,要求 Model 改变状态 ;

    3. Model 将新的数据发送到 View,用户得到反馈。

    MVC流程:

    MVC流程一共有两种,在日常开发中都会使用到。

    一种是通过 View 接受指令,传递给 Controller,然后对模型进行修改或者查找底层数据,最后把改动渲染在视图上。
    这里写图片描述

    另一种是通过controller接受指令,传给Controller:
    这里写图片描述

    MVC优点:

    • 耦合性低,视图层和业务层分离,这样就允许更改视图层代码而不用重新编译模型和控制器代码。
    • 重用性高
    • 生命周期成本低
    • MVC使开发和维护用户接口的技术含量降低
    • 可维护性高,分离视图层和业务逻辑层也使得WEB应用更易于维护和修改
    • 部署快

    MVC缺点:

    • 不适合小型,中等规模的应用程序,花费大量时间将MVC应用到规模并不是很大的应用程序通常会得不偿失。

    • 视图与控制器间过于紧密连接,视图与控制器是相互分离,但却是联系紧密的部件,视图没有控制器的存在,其应用是很有限的,反之亦然,这样就妨碍了他们的独立重用。

    • 视图对模型数据的低效率访问,依据模型操作接口的不同,视图可能需要多次调用才能获得足够的显示数据。对未变化数据的不必要的频繁访问,也将损害操作性能。

    MVC应用:

    在web app 流行之初, MVC 就应用在了java(struts2)和C#(ASP.NET)服务端应用中,后来在客户端应用程序中,基于MVC模式,AngularJS应运而生。

    MVP

    MVP(Model-View-Presenter)是MVC的改良模式,由IBM的子公司Taligent提出。和MVC的相同之处在于:Controller/Presenter负责业务逻辑,Model管理数据,View负责显示只不过是将 Controller 改名为 Presenter,同时改变了通信方向。

    MVP特点:

    1. M、V、P之间双向通信。
    2. View 与 Model 不通信,都通过 Presenter 传递。Presenter完全把Model和View进行了分离,主要的程序逻辑在Presenter里实现。
    3. View 非常薄,不部署任何业务逻辑,称为”被动视图”(Passive View),即没有任何主动性,而 Presenter非常厚,所有逻辑都部署在那里。
    4. Presenter与具体的View是没有直接关联的,而是通过定义好的接口进行交互,从而使得在变更View时候可以保持Presenter的不变,这样就可以重用。不仅如此,还可以编写测试用的View,模拟用户的各种操作,从而实现对Presenter的测试–从而不需要使用自动化的测试工具。

    与MVC区别:

    这里写图片描述

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

    MVP优点:

    1. 模型与视图完全分离,我们可以修改视图而不影响模型;
    2. 可以更高效地使用模型,因为所有的交互都发生在一个地方——Presenter内部;
    3. 我们可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑。这个特性非常的有用,因为视图的变化总是比模型的变化频繁;
    4. 如果我们把逻辑放在Presenter中,那么我们就可以脱离用户接口来测试这些逻辑(单元测试)。

    MVP缺点:

    视图和Presenter的交互会过于频繁,使得他们的联系过于紧密。也就是说,一旦视图变更了,presenter也要变更。

    MVP应用:
    可应用与Android开发。

    MVVM

    MVVMModel-View-ViewModel的简写。微软的WPF(Windows Presentation Foundation–微软推出的基于Windows 的用户界面框架)带来了新的技术体验, 使得软件UI层更加细节化、可定制化。与此同时,在技术层面,WPF也带来了 诸如Binding(绑定)、Dependency Property(依赖属性)、Routed Events(路由事件)、Command(命令)、DataTemplate(数据模板)、ControlTemplate(控制模板)等新特性。MVVM模式其实是MV模式与WPF结合的应用方式时发展演变过来的一种新型架构模式。它立足于原有MVP框架并且把WPF的新特性糅合进去,以应对客户日益复杂的需求变化。

    这里写图片描述

    MVVM优点:

    MVVM模式和MVC模式类似,主要目的是分离视图(View)和模型(Model),有几大优点:

    1. 低耦合,视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的”View”上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。

    2. 可重用性,可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑。

    3. 独立开发,开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计,使用Expression Blend可以很容易设计界面并生成xml代码。

    4. 可测试,界面向来是比较难于测试的,而现在测试可以针对ViewModel来写。

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

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

    本文由玉刚说写作平台提供写作赞助

    原作者:Zackratos

    版权声明:本文版权归微信公众号 玉刚说 所有,未经许可,不得以任何形式转载

    什么是 MVP

    MVP 全称:Model-View-Presenter ;MVP 是从经典的模式 MVC 演变而来,它们的基本思想有相通的地方:Controller/Presenter 负责逻辑的处理,Model 提供数据,View 负责显示。

    为什么要使用 MVP

    在讨论为什么要使用 MVP 架构之前,我们首先要了解传统的 MVC 的架构的特点及其缺点。

    首先看一下 MVC 架构的模型图,如下

    mvc

    这个图很简单,当 View 需要更新时,首先去找 Controller,然后 Controller 找 Model 获取数据,Model 获取到数据之后直接更新 View。

    在 MVC 里,View 是可以直接访问 Model 的。从而,View 里会包含 Model 信息,不可避免的还要包括一些业务逻辑。 在 MVC 模型里,更关注的 Model 的不变,而同时有多个对 Model 的不同显示,即 View。所以,在 MVC 模型里,Model 不依赖于 View,但是View 是依赖于 Model 的。不仅如此,因为有一些业务逻辑在 View 里实现了,导致要更改 View 也是比较困难的,至少那些业务逻辑是无法重用的。

    编者按:大多数情况下,View和Model都不会直接交互,而是通过Controller来间接交互。

    这样说可能会有点抽象,下面通过一个简单的例子来说明。

    假设现在有这样一个需求,Activity 中有一个 Button 和一个 TextView,点击 Button 时会请求网络获取一段字符串,然后把字符串显示在 TextView 中,按照正常的逻辑,代码应该这么写

    public class MVCActivity extends AppCompatActivity {
    
        private Button button;
        private TextView textView;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_test);
            button = findViewById(R.id.button);
            textView = findViewById(R.id.text_view);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    new HttpModel(textView).request();
                }
            });
        }
    }
    
    
    
    public class HttpModel {
        private TextView textView;
    
        public HttpModel(TextView textView) {
            this.textView = textView;
        }
    
        private Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                textView.setText((String) msg.obj);
            }
        };
    
        public void request() {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(2000);
                        Message msg = handler.obtainMessage();
                        msg.obj = "从网络获取到的数据";
                        handler.sendMessage(msg);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }

    代码很简单,当点击 Button 的时候,创建一个 HttpModel 对象,并把 TextView 对象作为参数传入,然后调用它的 request 方法来请求数据,当请求到数据之后,切换到主线程中更新 TextView,流程完全符合上面的 MVC 架构图。

    但是这里有个问题,首先很显然,HttpModel 就是 Model 层,那么 View 层和 Controller 层呢,我们分析一下 View 层和 Model 层分别干了什么事,在本例中,View 层主要做的事就是当获取到网络数据的时候,更新 TextView,Controller 层主要做的事就是创建 HttpModel 对象并调用它的 request 方法,我们发现 MVCActivity 同时充当了 View 层和 Controller 层。

    这样会造成两个问题,第一,View 层和 Controller 层没有分离,逻辑比较混乱;第二,同样因为 View 和 Controller 层的耦合,导致 Activity 或者 Fragment 很臃肿,代码量很大。由于本例比较简单,所以这两个问题都不是很明显,如果 Activity 中的业务量很大,那么问题就会体现出来,开发和维护的成本会很高。

    如何使用 MVP

    既然 MVC 有这些问题,那么应该如何改进呢,答案就是使用 MVP 的架构,关于 MVP 架构的定义前面已经说了,下面看一下它的模型图

    mvp

    这个图也很简单,当 View 需要更新数据时,首先去找 Presenter,然后 Presenter 去找 Model 请求数据,Model 获取到数据之后通知 Presenter,Presenter 再通知 View 更新数据,这样 Model 和 View 就不会直接交互了,所有的交互都由 Presenter 进行,Presenter 充当了桥梁的角色。很显然,Presenter 必须同时持有 View 和 Model 的对象的引用,才能在它们之间进行通信。

    接下来用 MVP 的架构来改造上面的例子,代码如下

    interface MVPView {
        void updateTv(String text);
    }
    
    
    public class MVPActivity extends AppCompatActivity implements MVPView {
        private Button button;
        private TextView textView;
        private Presenter presenter;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_test);
            button = findViewById(R.id.button);
            textView = findViewById(R.id.text_view);
            presenter = new Presenter(this);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    presenter.request();
                }
            });
        }
    
        @Override
        public void updateTv(String text) {
            textView.setText(text);
        }
    }
    
    
    interface Callback {
        void onResult(String text);
    }
    
    
    public class HttpModel {
        private Callback callback;
    
        public HttpModel(Callback callback) {
            this.callback = callback;
        }
    
        private Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                callback.onResult((String) msg.obj);
            }
        };
    
        public void request() {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(2000);
                        Message msg = handler.obtainMessage();
                        msg.obj = "从网络获取到的数据";
                        handler.sendMessage(msg);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }
    
    
    public class Presenter {
        private MVPView view;
        private HttpModel model;
    
        public Presenter(MVPView view) {
            this.view = view;
            model = new HttpModel(new Callback() {
                @Override
                public void onResult(String text) {
                    Presenter.this.view.updateTv(text);
                }
            });
        }
    
        public void request() {
            model.request();
        }
    }

    简单解释一下上面的代码,首先创建一个 MVPView 的接口,它即时 View 层,里面有一个更新 TextView 的方法,然后让 Activity 实现这个接口,并复写更新 TextView 的方法。Model 层不再传入 TextView 了,而是传入一个回调接口 Callback,因为网络请求获取数据是异步的,在获取到数据之后需要通过 Callback 来通知 Presenter。Presenter 也很简单,首先在它的构造方法中,同时持有 View 和 Model 的引用,再对外提供一个 request 方法。

    分析一下上面代码执行的流程,当点击 Button 的时候,Presenter 调用 request 方法,在它的内部,通过 Model 调用 request 方法来请求数据,请求到数据之后,切换到主线程,调用 callback 的 onResult 方法来通知 Presenter,这时候 Presenter 就会调用 View 的 updateTv 方法来更新 TextView,完成了整个流程,可以发现,在整个过程从,View 和 Model 并没有直接交互,所有的交互都是在 Presenter 中进行的。

    注意事项

    接口的必要性
    可能有的同学会问,为什么要写一个 MVPView 的接口,直接把 Activity 本身传入到 Presenter 不行吗?这当然是可行的,这里使用接口主要是为了代码的复用,试想一下,如果直接传入 Activity,那么这个 Presenter 就只能为这一个 Activity 服务。举个例子,假设有个 App 已经开发完成了,可以在手机上正常使用,现在要求做平板上的适配,在平板上的界面显示效果有所变化,TextView 并不是直接在 Activity 中的,而是在 Fragment 里面,如果没有使用 View 的接口的话,那就需要再写一个针对 Fragment 的 Presenter,然后把整个过程再来一遍。但是使用 View 的接口就很简单了,直接让 Fragment 实现这个接口,然后复写接口里面的方法,Presenter 和 Model 层都不需要做任何改动。同理,Model 层也可以采用接口的方式来写。

    防止内存泄漏
    其实上面的代码存在内存泄漏的风险。试想一下,如果在点击 Button 之后,Model 获取到数据之前,退出了 Activity,此时由于 Activity 被 Presenter 引用,而 Presenter 正在进行耗时操作,会导致 Activity 的对象无法被回收,造成了内存泄漏,解决的方式很简单,在 Activity 退出的时候,把 Presenter 对中 View 的引用置为空即可。

    // Presenter.java
    public void detachView() {
        view = null;
    }
    
    // MVPActivity.java
    @Override
    protected void onDestroy() {
        super.onDestroy();
        presenter.detachView();
    }

    另外还有一个问题,虽然这里 Activity 不会内存泄漏了,但是当 Activity 退出之后,Model 中请求数据就没有意义了,所以还应该在 detachView 方法中,把 Handler 的任务取消,避免造成资源浪费,这个比较简单,就不贴代码了。

    MVP 的封装

    很显然,MVP 的实现套路是大致相同的,如果在一个应用中,存在大量的 Activity 和 Fragment,并且都使用 MVP 的架构,那么难免会有很多重复工作,所以封装就很有必要性了。

    在说 MVP 的封装之前,需要强调一点,MVP 更多的是一种思想,而不是一种模式,每个开发者都可以按照自己的思路来实现具有个性化的 MVP,所以不同的人写出的 MVP 可能会有一些差别,笔者在此仅提供一种实现思路,供读者参考。

    首先 Model、View 和 Presenter 都可能会有一些通用性的操作,所以可以分别定义三个对应的底层接口。

    interface BaseModel {
    }
    
    interface BaseView {
        void showError(String msg);
    }
    
    public abstract class BasePresenter<V extends BaseView, M extends BaseModel> {
        protected V view;
        protected M model;
    
        public BasePresenter() {
            model = createModel();
        }
    
        void attachView(V view) {
            this.view = view;
        }
    
        void detachView() {
            this.view = null;
        }
    
        abstract M createModel();
    }

    这里的 View 层添加了一个通用的方法,显示错误信息,写在接口层,可以在实现处按照需求来显示,比如有的地方可能会是弹出一个 Toast,或者有的地方需要将错误信息显示在 TextView 中,Model 层也可以根据需要添加通用的方法,重点来看一下 Presenter 层。

    这里的 BasePresenter 采用了泛型,为什么要这么做呢?主要是因为 Presenter 必须同时持有 View 和 Model 的引用,但是在底层接口中无法确定他们的类型,只能确定他们是 BaseView 和 BaseModel 的子类,所以采用泛型的方式来引用,就巧妙的解决了这个问题,在 BasePresenter 的子类中只要定义好 View 和 Model 的类型,就会自动引用他们的对象了。Presenter 中的通用的方法主要就是 attachView 和 detachView,分别用于创建 View 对象和把 View 的对象置位空,前面已经说过,置空是为了防止内存泄漏,Model 的对象可以在 Presenter 的构造方法中创建。另外,这里的 Presenter 也可以写成接口的形式,读者可以按照自己的喜好来选择。

    然后看一下在业务代码中该如何使用 MVP 的封装,代码如下

    interface TestContract {
    
        interface Model extends BaseModel {
            void getData1(Callback1 callback1);
            void getData2(Callback2 callback2);
            void getData3(Callback3 callback3);
        }
    
        interface View extends BaseView {
            void updateUI1();
            void updateUI2();
            void updateUI3();
        }
    
        abstract class Presenter extends BasePresenter<View, Model> {
            abstract void request1();
            abstract void request2();
            void request3() {
                model.getData3(new Callback3() {
                    @Override
                    public void onResult(String text) {
                        view.updateUI3();
                    }
                });
            }
        }
    }

    首先定义一个 Contract 契约接口,然后把 Model、View、和 Presenter 的子类分别放入 Contract 的内部,这里的一个 Contract 就对应一个页面(一个 Activity 或者一个 Fragment),放在 Contract 内部是为了让同一个页面的逻辑方法都放在一起,方便查看和修改。Presenter 中的 request3 方法演示了如何通过 Presenter 来进行 View 和 Model 的交互。

    接下来要做的就是实现这三个模块的逻辑方法了,在 Activity 或 Fragment 中实现 TextContract.View 的接口,再分别创建两个类用来实现 TextContract.Model 和 TextContract.Presenter,复写里面的抽象方法就好了。

    扩展:用 RxJava 简化代码

    上面的代码中,Model 层中的每个方法都传入了一个回调接口,这是因为获取数据往往是异步的,在获取的数据时需要用回调接口通知 Presenter 来更新 View。

    如果想要避免回调接口,可以采用 RxJava 的方式来 Model 获取的数据直接返回一个 Observable,接下来用 RxJava 的方式来改造前面的例子

    public class HttpModel {
        public Observable<String> request() {
            return Observable.create(new ObservableOnSubscribe<String>() {
                @Override
                public void subscribe(ObservableEmitter<String> emitter) throws Exception {
                    Thread.sleep(2000);
                    emitter.onNext("从网络获取到的数据");
                    emitter.onComplete();
                }
            }).subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread());
        }
    }
    
    
    public class Presenter {
        private MVPView view;
        private HttpModel model;
    
        public Presenter(MVPView view) {
            this.view = view;
            model = new HttpModel();
        }
    
        private Disposable disposable;
    
        public void request() {
            disposable = model.request()
                    .subscribe(new Consumer<String>() {
                        @Override
                        public void accept(String s) throws Exception {
                            view.updateTv(s);
                        }
                    }, new Consumer<Throwable>() {
                        @Override
                        public void accept(Throwable throwable) throws Exception {
    
                        }
                    });
        }
    
        public void detachView() {
            view = null;
            if (disposable != null && !disposable.isDisposed()) {
                disposable.dispose();
            }
        }
    }

    Model 的 request 方法直接返回一个 Observable,然后在 Presenter 中调用 subscribe 方法来通知 View 更新,这样就避免了使用回调接口。

    开源库推荐

    最后,推荐一个 MVP 架构的开源库,正如笔者所说,MVP 更多的是一种思想,所以 github 上关于 MVP 的开源库并不多,大多是在完整的 APP 内部自己封装的 MVP。如果想要比较简单的集成 MVP 的架构,笔者推荐这个库:
    https://github.com/sockeqwe/mosby
    它的使用方法比较简单,可以直接参考官方的 demo,接下来简单的分析一下作者的封装思想。

    首先 View 层和 Presenter 层分别有一个基础的接口

    public interface MvpView {
    }
    
    public interface MvpPresenter<V extends MvpView> {
    
      /**
       * Set or attach the view to this presenter
       */
      @UiThread
      void attachView(V view);
    
      /**
       * Will be called if the view has been destroyed. Typically this method will be invoked from
       * <code>Activity.detachView()</code> or <code>Fragment.onDestroyView()</code>
       */
      @UiThread
      void detachView(boolean retainInstance);
    }

    这里加 @UIThread 注解是为了确保 attachView 和 detachView 都运行在主线程中。
    然后业务代码的 Activity 需要继承 MvpActivity

    public abstract class MvpActivity<V extends MvpView, P extends MvpPresenter<V>>
        extends AppCompatActivity implements MvpView,
        com.hannesdorfmann.mosby3.mvp.delegate.MvpDelegateCallback<V,P> {
    
      protected ActivityMvpDelegate mvpDelegate;
      protected P presenter;
      protected boolean retainInstance;
    
      @Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getMvpDelegate().onCreate(savedInstanceState);
      }
    
      @Override protected void onDestroy() {
        super.onDestroy();
        getMvpDelegate().onDestroy();
      }
    
      @Override protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        getMvpDelegate().onSaveInstanceState(outState);
      }
    
      @Override protected void onPause() {
        super.onPause();
        getMvpDelegate().onPause();
      }
    
      @Override protected void onResume() {
        super.onResume();
        getMvpDelegate().onResume();
      }
    
      @Override protected void onStart() {
        super.onStart();
        getMvpDelegate().onStart();
      }
    
      @Override protected void onStop() {
        super.onStop();
        getMvpDelegate().onStop();
      }
    
      @Override protected void onRestart() {
        super.onRestart();
        getMvpDelegate().onRestart();
      }
    
      @Override public void onContentChanged() {
        super.onContentChanged();
        getMvpDelegate().onContentChanged();
      }
    
      @Override protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        getMvpDelegate().onPostCreate(savedInstanceState);
      }
    
      /**
       * Instantiate a presenter instance
       *
       * @return The {@link MvpPresenter} for this view
       */
      @NonNull public abstract P createPresenter();
    
      /**
       * Get the mvp delegate. This is internally used for creating presenter, attaching and detaching
       * view from presenter.
       *
       * <p><b>Please note that only one instance of mvp delegate should be used per Activity
       * instance</b>.
       * </p>
       *
       * <p>
       * Only override this method if you really know what you are doing.
       * </p>
       *
       * @return {@link ActivityMvpDelegateImpl}
       */
      @NonNull protected ActivityMvpDelegate<V, P> getMvpDelegate() {
        if (mvpDelegate == null) {
          mvpDelegate = new ActivityMvpDelegateImpl(this, this, true);
        }
    
        return mvpDelegate;
      }
    
      @NonNull @Override public P getPresenter() {
        return presenter;
      }
    
      @Override public void setPresenter(@NonNull P presenter) {
        this.presenter = presenter;
      }
    
      @NonNull @Override public V getMvpView() {
        return (V) this;
      }
    }

    MvpActivity 中持有一个 ActivityMvpDelegate 对象,它的实现类是 ActivityMvpDelegateImpl,并且需要传入 MvpDelegateCallback 接口,ActivityMvpDelegateImpl 的代码如下

    public class ActivityMvpDelegateImpl<V extends MvpView, P extends MvpPresenter<V>>
        implements ActivityMvpDelegate {
    
      protected static final String KEY_MOSBY_VIEW_ID = "com.hannesdorfmann.mosby3.activity.mvp.id";
    
      public static boolean DEBUG = false;
      private static final String DEBUG_TAG = "ActivityMvpDelegateImpl";
    
      private MvpDelegateCallback<V, P> delegateCallback;
      protected boolean keepPresenterInstance;
      protected Activity activity;
      protected String mosbyViewId = null;
    
      /**
       * @param activity The Activity
       * @param delegateCallback The callback
       * @param keepPresenterInstance true, if the presenter instance should be kept across screen
       * orientation changes. Otherwise false.
       */
      public ActivityMvpDelegateImpl(@NonNull Activity activity,
          @NonNull MvpDelegateCallback<V, P> delegateCallback, boolean keepPresenterInstance) {
    
        if (activity == null) {
          throw new NullPointerException("Activity is null!");
        }
    
        if (delegateCallback == null) {
          throw new NullPointerException("MvpDelegateCallback is null!");
        }
        this.delegateCallback = delegateCallback;
        this.activity = activity;
        this.keepPresenterInstance = keepPresenterInstance;
      }
    
      /**
       * Determines whether or not a Presenter Instance should be kept
       *
       * @param keepPresenterInstance true, if the delegate has enabled keep
       */
      static boolean retainPresenterInstance(boolean keepPresenterInstance, Activity activity) {
        return keepPresenterInstance && (activity.isChangingConfigurations()
            || !activity.isFinishing());
      }
    
      /**
       * Generates the unique (mosby internal) view id and calls {@link
       * MvpDelegateCallback#createPresenter()}
       * to create a new presenter instance
       *
       * @return The new created presenter instance
       */
      private P createViewIdAndCreatePresenter() {
    
        P presenter = delegateCallback.createPresenter();
        if (presenter == null) {
          throw new NullPointerException(
              "Presenter returned from createPresenter() is null. Activity is " + activity);
        }
        if (keepPresenterInstance) {
          mosbyViewId = UUID.randomUUID().toString();
          PresenterManager.putPresenter(activity, mosbyViewId, presenter);
        }
        return presenter;
      }
    
      @Override public void onCreate(Bundle bundle) {
    
        P presenter = null;
    
        if (bundle != null && keepPresenterInstance) {
    
          mosbyViewId = bundle.getString(KEY_MOSBY_VIEW_ID);
    
          if (DEBUG) {
            Log.d(DEBUG_TAG,
                "MosbyView ID = " + mosbyViewId + " for MvpView: " + delegateCallback.getMvpView());
          }
    
          if (mosbyViewId != null
              && (presenter = PresenterManager.getPresenter(activity, mosbyViewId)) != null) {
            //
            // Presenter restored from cache
            //
            if (DEBUG) {
              Log.d(DEBUG_TAG,
                  "Reused presenter " + presenter + " for view " + delegateCallback.getMvpView());
            }
          } else {
            //
            // No presenter found in cache, most likely caused by process death
            //
            presenter = createViewIdAndCreatePresenter();
            if (DEBUG) {
              Log.d(DEBUG_TAG, "No presenter found although view Id was here: "
                  + mosbyViewId
                  + ". Most likely this was caused by a process death. New Presenter created"
                  + presenter
                  + " for view "
                  + getMvpView());
            }
          }
        } else {
          //
          // Activity starting first time, so create a new presenter
          //
          presenter = createViewIdAndCreatePresenter();
          if (DEBUG) {
            Log.d(DEBUG_TAG, "New presenter " + presenter + " for view " + getMvpView());
          }
        }
    
        if (presenter == null) {
          throw new IllegalStateException(
              "Oops, Presenter is null. This seems to be a Mosby internal bug. Please report this issue here: https://github.com/sockeqwe/mosby/issues");
        }
    
        delegateCallback.setPresenter(presenter);
        getPresenter().attachView(getMvpView());
    
        if (DEBUG) {
          Log.d(DEBUG_TAG, "View" + getMvpView() + " attached to Presenter " + presenter);
        }
      }
    
      private P getPresenter() {
        P presenter = delegateCallback.getPresenter();
        if (presenter == null) {
          throw new NullPointerException("Presenter returned from getPresenter() is null");
        }
        return presenter;
      }
    
      private V getMvpView() {
        V view = delegateCallback.getMvpView();
        if (view == null) {
          throw new NullPointerException("View returned from getMvpView() is null");
        }
        return view;
      }
    
      @Override public void onDestroy() {
        boolean retainPresenterInstance = retainPresenterInstance(keepPresenterInstance, activity);
        getPresenter().detachView(retainPresenterInstance);
        if (!retainPresenterInstance && mosbyViewId != null) {
          PresenterManager.remove(activity, mosbyViewId);
        }
    
        if (DEBUG) {
          if (retainPresenterInstance) {
            Log.d(DEBUG_TAG, "View"
                + getMvpView()
                + " destroyed temporarily. View detached from presenter "
                + getPresenter());
          } else {
            Log.d(DEBUG_TAG, "View"
                + getMvpView()
                + " destroyed permanently. View detached permanently from presenter "
                + getPresenter());
          }
        }
      }
    
      @Override public void onPause() {
    
      }
    
      @Override public void onResume() {
    
      }
    
      @Override public void onStart() {
    
      }
    
      @Override public void onStop() {
    
      }
    
      @Override public void onRestart() {
    
      }
    
      @Override public void onContentChanged() {
    
      }
    
      @Override public void onSaveInstanceState(Bundle outState) {
        if (keepPresenterInstance && outState != null) {
          outState.putString(KEY_MOSBY_VIEW_ID, mosbyViewId);
          if (DEBUG) {
            Log.d(DEBUG_TAG,
                "Saving MosbyViewId into Bundle. ViewId: " + mosbyViewId + " for view " + getMvpView());
          }
        }
      }
    
      @Override public void onPostCreate(Bundle savedInstanceState) {
      }
    }

    代码有点长,但是逻辑还是比较清晰的,它其实就是在 onCreate 方法中根据不同的情况来创建 Presenter 对象,并通过 MvpDelegateCallback 的 setPresenter 方法把它保存在 MvpDelegateCallback 中,这里的 MvpDelegateCallback 就是 MvpActivity 本身。另外可以在 Activity 的各个生命周期方法中加入需要实现的逻辑。

    可能有的同学会问,为什么没有 Model 呢?其实这里的代码主要是对 Presenter 的封装,从作者给出的官方 demo 中可以发现,Model 和 View 都是需要自己创建的。

    这里只做一个简单的分析,有兴趣的同学可以自己查看它的源码,再强调一遍,MVP 更多的是一种思想,不用局限于某一种套路,可以在领悟了它的思想之后,写出自己的 MVP。

    欢迎关注微信公众号,接收第一手技术干货:

    展开全文
  • 浅谈 MVP in Android

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

    千次阅读 2017-06-26 00:05:01
    说到 MVP ,大家应该都不陌生了,由于其高度解耦等有点,越来越多的项目使用这个设计模式;然而,有点虽在,缺点也不少,其中一个就是类多了很多,而且 V 与 P 直接要项目通信,那么 P 就得持有 V 得实例,但如果 ...
  • MVP

    2017-05-23 12:04:02
    MVP ###为什么需要MVP 尽量简单 大部分的安卓应用只使用View-Model结构,程序员现在更多的是和复杂的View打交道而不是解决业务逻辑。当你在应用中只使用Model-View时,到最后,你会发现“所有的事物都被连接到...
  • MVC、MVP、MVVM,我到底该怎么选?

    万次阅读 多人点赞 2018-07-03 20:42:29
    本文由玉刚说写作平台提供写作赞助 原作者:AndroFarmer 版权声明:本文版权归微信...比如看了好多篇文章都搞不懂MVC到底是个啥本来想写个MVP写着写着就变成MVC了,到底Databing和MVVM之间有啥见不得人的关系...
  • Android MVP开发模式 google 官方Mvp架构详解(转)

    万次阅读 多人点赞 2017-03-24 09:19:32
    Google官方MVP Sample代码解读关于Android程序的构架, 当前最流行的模式即为MVP模式, Google官方提供了Sample代码来展示这种模式的用法.Repo地址: android-architecture.本文为阅读官方sample代码的阅读笔记和分析....
  • Android官方MVP架构解读

    万次阅读 多人点赞 2016-05-22 22:24:28
    对于MVP (Model View Presenter)架构是从著名的MVC(Model View Controller)架构演变而来的。而对于Android应用的开发中本身可视为一种MVC架构。通常在开发中将XML文件视为MVC中的View角色,而将Activity则视为MVC中...
  • Android MVP(一)架构介绍与使用入门

    万次阅读 多人点赞 2019-07-05 18:01:55
    博主声明: 转载请在开头附加本文链接及作者信息,并标记为转载。本文由博主威威喵原创,请多支持与指教。 ... MVP 架构系列文章: ...Android MVP 架构(一)MVP 架构...Android MVP 架构(二)MVP 之 BaseMVP 基础框...
  • Android MVP(二)BaseMVP 基础框架设计

    万次阅读 多人点赞 2019-07-06 19:29:10
    博主声明: 转载请在开头附加本文链接及作者信息,并标记为转载。本文由博主威威喵原创,请多支持与指教。 ... MVP 架构系列文章: ...Android MVP 架构(一)MVP 架构...Android MVP 架构(二)MVP 之 BaseMVP 基础框...
  • android MVP——mvp架构的应用和优化

    千次阅读 2016-05-27 20:06:45
    MVP架构在android还是很好用的。我也在试着将mvp用在项目中。下面我就来说说mvp模式的应用和优化。mvp模式的概念MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,...
  • Android mvp 架构的自述

    千次阅读 多人点赞 2016-03-17 17:51:07
    最近发现再也无法忍受越来越臃肿的Activity代码,越来越来混乱的Activity层的代码,投入到了MVP的怀抱。目前来看MVP的架构还是很适合Android的,在这里记录一下一点心得,希望都给想用MVP的人一点帮助。老的MVC架构...

空空如也

1 2 3 4 5 ... 20
收藏数 66,851
精华内容 26,740
关键字:

mvp