继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

MVP架构从头撸一遍~

陪伴而非守候
关注TA
已关注
手记 358
粉丝 62
获赞 285

背景

首先,项目重构撸了两三天的网络部分,采用的Retrofit+RxJava,这部分后面打算搞个时间再说,然后想到整体架构的时候,我决定采用MVP模式,观摩了googleMVP-TODO项目。比较贱的是,我又想加入Dagger2来做到更加解耦,看到了MVP-TODO中也有一个分支叫做MVP-Dagger。word天啊,业界良心!!!

看了之后,里面的套路还是用一个ContractViewPresenter绑定起来,这样说吧,本来的MVP就可能会增加很多类,但是这个MVP + Dagger2 的规模达到了要做一个页面可能要添加5个类,这个我可不能接受,想了好久,终于让我在phphub-android中找到了解决方案,这里面引用了一个库用于简化MVP,这个库的名字叫做nucleus,这个库采用一种比较巧妙的方法把View和Presenter绑定起来,只需要一个Actiivty和一个Presenter即可,不用声明一个Interface来进行绑定。同时这个库支持RxJava,我看了一下WIKI,说的是可以支持APP异常推出的数据保存和恢复,有兴趣的可以传送过去看看。传送门----nucleus

好了,吹水吹得够多了,下面是正题。

本人是基于nucleus把里面的核心部分抽出来,放到自己的项目中去。


准备工作

首先我们需要定义一个通用的Presenter

 public class Presenter<View> {
     View view;
     public View getView(){
     return view;
     }
     public void setView(View view){
     this.view = view;
     }
 }

很简单,里面就一个View的泛型

然后我们定义一个PresenterFactory接口用于创建Presenter

 public interface PresenterFactory<P extends Presenter> {
     P createPresenter();
 }

接下来,耐心看,目前不需要知道为什么要这样做,先跟着看,后面会讲解流程的。

定义一个ViewWithPresenter接口:

 public interface ViewWithPresenter<P extends Presenter> {

     PresenterFactory<P> getPresenterFactory();

     void setPresenterFactory(PresenterFactory<P> factory);

     P getPresenter();

 }

还要定义一个注解:

 @Retention(RetentionPolicy.RUNTIME)
 public @interface RequirePresenter {
     Class<? extends Presenter> value();
 }

定义一个代理类:

public class PresenterDelegate<P extends Presenter> {
     private PresenterFactory<P> presenterFactory;
     private P presenter;

     public PresenterDelegate(@Nullable PresenterFactory<P> presenterFactory) {
         this.presenterFactory = presenterFactory;
     }

     @Nullable
     public PresenterFactory<P> getPresenterFactory() {
         return presenterFactory;
     }

     public void setPresenterFactory(@Nullable PresenterFactory<P> presenterFactory) {
         this.presenterFactory = presenterFactory;
     }

     public P getPresenter() {
         if (presenterFactory != null) {
             if (presenter == null) {
                    presenter = presenterFactory.createPresenter();
             }
        }
       return presenter;
     }

     public void onCreate(Object view){
         getPresenter();
         if(presenter != null){
             presenter.setView(view);
         }
      }
}

定义一个实现了PresenterFactory的实现类:

public class ReflectionPresenterFactory<P extends Presenter> implements PresenterFactory<P> {

 private Class<P> presenterClass;

 @Nullable
 public static <P extends Presenter> ReflectionPresenterFactory<P> fromViewClass(Class<?> viewClass) {
     RequirePresenter annotation = viewClass.getAnnotation(RequirePresenter.class);
     //noinspection unchecked
     Class<P> presenterClass = annotation == null ? null : (Class<P>)annotation.value();
     return presenterClass == null ? null : new ReflectionPresenterFactory<>(presenterClass);
 }

 public ReflectionPresenterFactory(Class<P> presenterClass) {
     this.presenterClass = presenterClass;
 }

 @Override
 public P createPresenter() {
     try {
         return presenterClass.newInstance();
     }
     catch (Exception e) {
         throw new RuntimeException(e);
     }
   }
}

接着到高潮了,定义一个Activity,我暂且跟着那个框架命名:

public class NucleusActivity<P extends Presenter> extends AppCompatActivity implements ViewWithPresenter<P> {

 private PresenterDelegate<P> presenterDelegate =
 new PresenterDelegate<>(ReflectionPresenterFactory.<P>fromViewClass(getClass()));

 @Override
 protected void onCreate(@Nullable Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     presenterDelegate.onCreate(this);
 }

 @Override
 public PresenterFactory<P> getPresenterFactory() {
     return presenterDelegate.getPresenterFactory();
 }

 @Override
 public void setPresenterFactory(PresenterFactory<P> factory) {
     presenterDelegate.setPresenterFactory(factory);
 }

 @Override
 public P getPresenter() {
     return presenterDelegate.getPresenter();
 }
}

嗯,这样就把东西构建完毕了,现在只要要你定义一个BaseActivity继承NucleusActivity即可:

public class BaseActivity<P extends Presenter> extends NucleusActivity<P> {

}

假设我有一个MainActivity和一个MainPresenter的话,要这样写:

 @RequirePresenter(MainPresenter.class)
 public class MainActivity extends BaseActivity<MainPresenter> {



 }

这样写了之后基本上就可以绑定ViewPresenter了,为什么会这样呢。

我们来撸一撸代码:

我们在NucleusActivity里面的onCreate方法中调用了PresenterDelegateonCreate方法。我们具体看看:

 @Override
 protected void onCreate(@Nullable Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     presenterDelegate.onCreate(this);
 }

再看回这个delegata是什么东西:

 presenterDelegate =new PresenterDelegate<>
                       (ReflectionPresenterFactory.<P>fromViewClass(getClass())

这个代理类代理的是ReflectionPresenterFactory.<P>fromViewClass(getClass())这个PresenterFactory

 @Nullable
 public static <P extends Presenter> ReflectionPresenterFactory<P> fromViewClass(Class<?> viewClass) {
 RequirePresenter annotation = viewClass.getAnnotation(RequirePresenter.class);
 //noinspection unchecked
 Class<P> presenterClass = annotation == null ? null : (Class<P>)annotation.value();
 return presenterClass == null ? null : new ReflectionPresenterFactory<>(presenterClass);
 }

当我们在MainActivity上使用的@RequirePresenter的时候,我们就可以在这里得到我们声明的Presenterclass对象,然后createPresenter的实现如下:

 @Override
 public P createPresenter() {
     try {
         return presenterClass.newInstance();
     }
     catch (Exception e) {
         throw new RuntimeException(e);
     }
 }

可以看到,直接就是class.newInstance()出来的Presenter

再看回PresenterDelegateonCreate方法:

 public void onCreate(Object view){
     getPresenter();
     if(presenter != null){
         presenter.setView(view);
     }
 }

首先调用了getPresent()用我上面说的方法创建了Presenter,然后,调用了setView方法,这个View其实就是MainActivity的实例。这样Presenter就持有了View的对象。P和V已经绑定。

V 和 P 是什么时候绑定的呢?

我们知道,Activity实现了ViewWithPresenter接口,里面就有一个getPresenter方法,这个方法调用的就是PresenterDetagategetPresenter()方法

 @Override
 public P getPresenter() {
     return presenterDelegate.getPresenter();
 }

delegate.getPresenter()的实现:

 public P getPresenter() {
     if (presenterFactory != null) {
         if (presenter == null) {
             presenter = presenterFactory.createPresenter();
         }
     }
  return presenter;
 }

这样的话,我们在MainActivity中通过getPresenter就可以获取Presenter的实例,而在Presenter中调用了getView就能获取MainActivity的实例。实现了双向绑定。


总结

可能我上面说的逻辑有点绕,也说得不太明白。不过这个东西本来就有点绕,把代码打出来,看多几遍就自然能理解它的工作流程。主要我是觉得,这种方案能减少很多不必要的类。值得借鉴参考。


注意

我在实践的过程中,发现Activity其实还存在两个方法getPresenterFacotry()setPresenterFacory(),默认的Activity是在onCreate的已经使用代理类创建了Presenter,所以如果你需要自定义一个PresenterFacotry来替代默认的话,需要在onCreate之前(在BaseActivitysuper.onCreate()之前调用即可),这个其实是在onCreate的时候已经使用PresenterFactory创建了Presenter,并且已经实现了绑定,所以你再使用那两个方法的话,得到的不是同一个实例。

我遇到这个坑是因为我添加了Dagger2,需要注入Presenter所以遇到这个问题(其实Nucleus里面是在onResume方法里面进行绑定P和V的,但是我们开发习惯是通常在onCreate的时候就有可能使用到Presenter,为了防止空指针,我放在了onCreate里面,至于Nucleus是如何处理这个问题,我没有深入去理解过)

原文链接:http://www.apkbus.com/blog-822717-76562.html

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP