背景
首先,项目重构撸了两三天的网络部分,采用的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是如何处理这个问题,我没有深入去理解过)
随时随地看视频