撸一撸MVP吧

吹吹水

最近刚刚上班,几天连续加班,做重构,满心激情,像打了鸡血一样。连续几天没去健身了,心里痒痒的,今天果断不加班,回来去健身。回到家里看着有些时间,这几天做的东西也有点心得,赶紧写写东西记录一下。

背景

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

实例代码:https://github.com/Jamlh/Sample

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值