看过mvp结构的人都知道,在官方版本的mvp里面有很多大量的接口定义,没错 就是接口,没次都要写大量的接口,时间久了会觉得很烦,这里简化了一个mvp的标准写法少了很多接口定义,至少我现在项目中正在这么使用,不过这个MVP目前还有一层没有挖掘,那就是M层,不过在看了[架构向] 谈Android中DTO -> VO的重要性文章以后,感觉可以用在现在的M层中,做DTO,这样让P层在拿到数据以后只专心处理逻辑,而不用判断太多的数据校验。
先来看看传统的MVP的结构走向图:
这次的简化来源于经过实践发现,大部分Presenter------>View的都只是铺铺数据,而本着一个View拥有一个Presenter的原则,所以简化过后的结构走向还是原来的结构走向,只是少了一点接口而已,也算的上是对MVP的一种简化的封装。
首先我们先来看看BasePresenter类:
public abstract class BasePresenter<T extends BaseView> {
private WeakReference<T> weakReference;
public BasePresenter(T baseView) {
setView(baseView);
}
public T getView() {
return weakReference!=null?weakReference.get():null;
}
public void setView(T view) {
this.weakReference = new WeakReference<>(view);
}
public void recycle(){
if(weakReference!=null){
weakReference.clear();
weakReference=null;
}
}
}
所有的Presenter都需要继承这个BasePresenter,更具结构类图,此类中需要依赖一个视图层的接口,因此在继承此类的时候通过泛型看到需要传入一个继承自BaseView接口的接口。没错Presenter层在向View通信的时候任然是需要依靠接口来通信的,这里取消了Presneter和Model的接口依赖关。从大部分实践上来看,感觉这两曾的的依赖关系并不是很重要,所以取消掉了,当然也有可能是我还没发现P与M之间的依赖好处。如果您有不同的看法可以在评论区留言,大家共同学习互相借鉴。在这里,M层只是一个简单的JavaBean。当然如果加上本文开头说的DTO,M曾的意义就体现出来了,不过目前还没有这么做。
在BasePresenter抽象类中,我们还看到了一个recycle()
方法,这个方法是用来清楚View的依赖。因为很多时候Presenter中处理的都是异步耗时操作,如果此时用户等不耐烦了,推出了当然的界面,那么就很有可能会造成泄漏且如果您使用的是butterknife
这个框架的话,挥发这个框架也会提共一个unbind()
方法,如果这里不清楚View的依赖的话,当用户退出界面就会发生NullPointException
的异常。所以BasePresenter中提供了这个方法。继承之后通过使用getView方法获取依赖的view,注意 使用前需要判断非空。
现在来看看BaseView接口:
public interface BaseView {
void dialogShow(String message);
void dialogShow();
void dialogDissmiss();
}
这个接口很简单仅仅只是一个基类,定义了一些公共的方法如这里dialog的显示与关闭。
由于大部分View层都只是铺数据,区别只是数据的类型不一样,因此这里还提供几个普通的BaseView接口,
处理一种数据的接口
public interface BaseView1<T> extends BaseView{
void getData(T data);
}
处理两种数据类型的接口:
public interface BaseView2<T,J> extends BaseView{
void getData(T data);
void getData2(J data);
}
等等。这只是偶尔用用的,因为我这里出现的平率比较多所以才加上这写接口的。其实只需要一个BaseView接口就好了,在定义View层接口的时候基础BaseView就行。
这里有一个使用的例子,一般项目都会有一个BaseActivity之类的东西。
public class BaseActivity<T extends BasePersent<? extends BaseView>> extends AppCompatActivity implements BaseView {
public static String TAG;
private T presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TAG=getClass().getCanonicalName();
}
@Override
protected void onDestroy() {
if(presenter!=null){
presenter.recycle();
}
super.onDestroy();
}
public T getPresenter() {
return presenter;
}
public void setPresenter(T presenter) {
this.presenter = presenter;
}
@Override
public void showLoading(String message) {
Log.i(TAG,"dialog show "+message);
}
@Override
public void hideLoading() {
Log.i(TAG,"dialog hiden");
}
}
这里BaseActivity实现了BaseView接口,并实现了里面的公共方法(这里是dialog的显示与关闭)。在onDestory()
方法中,现调用了presenter中的recycle()
方法来释放引用,这样不管presenter中做了什么耗时操作只要在getView之前判断了非空,就避免了泄漏的风险,已经空指针异常的风险了。
在来看看我们View所依赖的Presenter
public class DemoPersent extends BasePersent<DemoPersent.DemoView> {
Service service;
public DemoPersent(DemoView baseView) {
super(baseView);
service=ZillApi.NormalAdapter.create(Service.class);
}
public void doOnClick(String classId){
getView().showLoading("正在加载");
//做了一部分的耗时操作
service.getMainDate(classId, new CallBack() {
@Override
public void success(String str) {
//取消Dialog
if(getView()!=null){
getView().hideLoading();
}
//处理一些数据.......
//返回数据
if(getView()!=null){
getView().updateBtn2(str);;
}
}
});
}
public void doSomthing(){
String str="haha22222";
getView().updateBtn1(str);
}
//Presener所以来的View
public interface DemoView extends BaseView {
void updateBtn1(String str);
void updateBtn2(String str);
}
}
下面看看具体的Activity
public class MainActivity extends BaseActivity<DemoPresenter> implements DemoPresenter.DemoView {
TextView btn,btn1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//指定当前Activity需要的Presneter
setPresenter(new DemoPresenter(this));
btn= (TextView) findViewById(R.id.btn);
btn1= (TextView) findViewById(R.id.btn1);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getPresenter().doOnClick("dsadas");
}
});
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getPresenter().doSomthing();
}
});
}
@Override
public void updateBtn1(String str) {
btn.setText(str);
}
@Override
public void updateBtn2(String str) {
btn1.setText(str);
}
}
如此在也不要担心泄漏的风险和空指针的问题了。还少些了很多接口,代码也简洁多了。在View值会看到很多傻瓜式的铺数据的过程。
在此结构的基础上,还可以引入DataBind以及本文开头说的DTO等进行进一步的简化。Model层还有很大的提升空间。