背景
首先,项目重构撸了两三天的网络部分,采用的Retrofit
+RxJava
,这部分后面打算搞个时间再说,然后想到整体架构的时候,我决定采用MVP模式,观摩了google
的MVP-TODO
项目。比较贱的是,我又想加入Dagger2
来做到更加解耦,看到了MVP-TODO
中也有一个分支叫做MVP-Dagger
。word天啊,业界良心!!!
看了之后,里面的套路还是用一个Contract
把View
和Presenter
绑定起来,这样说吧,本来的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> { }
这样写了之后基本上就可以绑定View
和Presenter
了,为什么会这样呢。
我们来撸一撸代码:
我们在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
的时候,我们就可以在这里得到我们声明的Presenter
的class
对象,然后createPresenter
的实现如下:
@Override public P createPresenter() { try { return presenterClass.newInstance(); } catch (Exception e) { throw new RuntimeException(e); } }
可以看到,直接就是class.newInstance()
出来的Presenter
再看回PresenterDelegate
的onCreate
方法:
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
方法,这个方法调用的就是PresenterDetagate
的getPresenter()
方法
@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
之前(在BaseActivity
的super.onCreate()
之前调用即可),这个其实是在onCreate
的时候已经使用PresenterFactory
创建了Presenter
,并且已经实现了绑定,所以你再使用那两个方法的话,得到的不是同一个实例。
我遇到这个坑是因为我添加了Dagger2
,需要注入Presenter
所以遇到这个问题(其实Nucleus
里面是在onResume
方法里面进行绑定P和V的,但是我们开发习惯是通常在onCreate
的时候就有可能使用到Presenter
,为了防止空指针,我放在了onCreate
里面,至于Nucleus
是如何处理这个问题,我没有深入去理解过)