首先我们需要知道mvp所代表的含义,m即model可以理解成用来获取数据和处理数据,v即view可以看成activity和fragment用来显示数据和处理交互,p即presenter可以理解成用来提供数据。
三者关系:m层用来获取数据然后将数据提供给p层,p层拿到数据后通过v层展示,其中m层和v层是不能直接进行交互的,通过p层这个桥梁进行交互。这其中p层会持有v层和m层的引用。(先读懂)
理解上面的说法下面我们直接上手代码:
为了减少接口文件我们可以把接口都声明在contract内
public interface contentcontract { interface model { } interface view { } interface presenter { } } //这样我们不需要写三个接口文件
然后分别实现三个接口与之对应的m层,v层,p层
//model public class contentmodel implements contentcontract.model { } //view public class mainactivty extends basequickactivty implements contentcontract.view { } //presenter public class contentpresenter implements contentcontract.presenter { }
首先我们需要考虑的是在v层我们需要做一些什么处理,然后在定义我们的方法。假如我们需要获取kb88凯时d88尊龙官网手机app官网登录首页的banner数据,这时候就可以在view中声明一个方法用来接收banner数据。
public interface contentcontract { interface model { } interface view { void getbanner(string str); } interface presenter { } } //这时候activity实现此方法 public class mainactivty extends basequickactivty implements contentcontract.view { @override public void getbanner(string str) { } }
当v层已经有了接收数据的方法时,那么数据从何而来了?我们在之前说过m层是用来获取数据的 所以我们可以在m层中定义一个请求网络的方法。
// public class contentmodel implements contentcontract.model { //获取banner public void sendhttpbannerdata(onlisteneron){ //这里需要考虑一个问题,就是每次获取请求后的数据,我们需要传递给p层,所以需要一个回调处理 //我们可以对m层进一步封装下 //代码示例 okgo.post().ex(new callback(){ public void onsucces(string str){ on.onsuccess(str); } public void onfail(){ on.onfail(); } }); } } //封装后的modle层 ,先提取一个基类basemodel public interface basemodel { interface onlistener { void onsuccess(t t); void onfail(int code, string msg); } } //modle实现 interface model extends basemodle { }
现在数据获取的方式已经有了,那怎么传递给p层呢?我们在之前也说过p层会持有m层的引用,所以我们可以在p层中调用层方法。
public class contentpresenter implements contentcontract.presenter { private contentmodel mmodel; private contentcontract.view mview; //当初始化的时候 同时持有v层和m层引用 public contentpresenter(contentcontract.view m) { mview=m; mmodel = new contentmodel(); } //定义一个send方法,在该方法中调用m层的请求数据方法 public void send(){ mmodel.sendhttpbannerdata(new basemodel.onlistener() { @override public void onsuccess(string s) { //这里就可以直接使用v层方法处理数据,在v层中我们已经实想该函数 mview.getbanner(s); } @override public void onfail(int code, string msg) { } }); } }
最后一步就是初始化p
public class mainactivty extends basequickactivty implements contentcontract.view { @override protected void oncreate(@nullable bundle savedinstancestate) { super.oncreate(savedinstancestate); //初始化p contentpresenter contentpresenter = new contentpresenter(this); contentpresenter.send();//调用p层的send方法 开始请求数据 } @override public void getbanner(string str) { } }
这样我们就可以交互了,在接口中我们可以根据自己的需求增加方法,可以提供基类,这样没必要每次都重写方法,可以将一些通用的放在基类中。(可以先消化下,接下来我们做进一步的处理和避免内存泄漏问题)
我们分析下不足之处。
每一个presenter都需要每次重写相同代码,手动释放p等不足之处。所以我们先从presenter入手.
/** * 基类 presenter 绑定view * * @param*/ public abstract class basepresenter { //弱引用 private weakreference mweakreference; private referencequeue mreferencequeue = new referencequeue<>(); /** * 添加view进入队列 * * @param t */ public void attachview(t t) { mweakreference = new weakreference (t); } public t getview() { return mweakreference.get(); } /** * 判断是否绑定过view * * @return true 绑定 */ public boolean isviewattachecd() { return mweakreference != null && mweakreference.get() != null; } /** * 清除view,这样不用每次手动释放 */ public void deleteattach() { if (mweakreference != null) { mweakreference.clear(); mweakreference = null; } } }
接着我们改进activity或者fragment的基类base
** * activity 基类 * v 代表 view * t presenter */ public abstract class basequickactivity> extends appcompatactivity { protected t mpresenter; @override protected void oncreate(@nullable bundle savedinstancestate) { super.oncreate(savedinstancestate); mpresenter = createpresenter(); //这里做一下非空判断 有可能某些模块不需要mvp模式 if (mpresenter != null) { mpresenter.attachview((v) this); } } protected abstract t createpresenter(); @override protected void ondestroy() { super.ondestroy(); if (mpresenter != null) { mpresenter.deleteattach(); } } } //fragment 一样的写法
这样我们基本上完善了mvp模式。mvp给我带来的好处很多,高度解耦,代码结构清晰(以前ac或者ft可以达到上千行代码,现在都交给了p和m),便于测试(不会)。但是同时也有缺点,第一感知就是类增多了。第二感知就是在交互时有些时候不方便。
上述结构体还是可以更加完善的,可以用eventbus或者rxjava用于沟通的桥梁和数据分发。