Android MVP-编程思想4(AOP思想-动态代理运用,反射创建M层实例对象)

前言

通过一个小的登录功能模块案例,帮助大家了解MVP。最终实现一个结合Rxjava2,Retrofit 的MVP通用框架。代码放到github上。(如有错误之处,请在评论区指出,谢谢。如果感觉写的不错,请点赞,关注,谢谢。)

目录:

Android MVP-编程思想1(什么是MVC-MVP-MVVM模式?)
Android MVP-编程思想2(代码实现初级版)
Android MVP-编程思想3(内存泄露问题处理,基类封装,有没有必要再使用软引用?)
Android MVP-编程思想4(AOP思想-动态代理运用,反射创建M层实例对象)
Android MVP-编程思想5(如何处理多个P层的问题?)
Android MVP-编程思想6(依赖注入多个P层优化—注解,反射)
Android MVP-编程思想7(为什么使用代理类抽取通用方法而不是工具类?,基类BaseMvpFragment)

未完待续--------
Android MVP-编程思想8(集成Rxjava2,Retrofit)

上一节讲解了如何处理内存泄露,如何做基类封装。这一节学习如何使用动态代理处理重复逻辑,以及运用泛型创建M层的实例对象。

AOP思想-动态代理运用

在第二小节中我们已经提到了下面的问题:网络请求是耗时操作,我们 Presenter 层持有了 View 层的引用,也就是 Activity 的引用,在网络请求过程中,Activity被用户或者系统关闭,这时 View 相当于被摧毁了,如果不进行判断 View 引用是否为空,当数据返回时,就会造成空指针异常,所以每次都要进行判空才合理。
每次进行非空判断是不是很繁琐?能不能做统一处理?考虑使用动态代理进行处理,java动态代理需要使用接口辅助实现。这里的 View 类型是一个接口(V extends IBaseView),动态代理完全就可以做到统一的空类型判断,

public abstract class BasePresenter<V, M> {
    private SoftReference<V> mViewReference;
    protected V mView;//mProxyView
    protected M mModel;

    protected void attachView(final V view) {
        mViewReference = new SoftReference<V>(view);
//        mView = mViewReference.get();
        mModel = createModel();
        //AOP思想,统一做非空判断
        mView = (V) Proxy.newProxyInstance(view.getClass().getClassLoader(), view.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if (mViewReference == null || mViewReference.get() == null) {
                    return null;
                }
                Object object = method.invoke(mViewReference.get(), args);
                return object;
            }
        });
    }

    protected void detachView() {
        mViewReference.clear();
        mViewReference = null;
        mView = null;
        mModel = null;
    }

    protected abstract M createModel();

}
反射创建M层实例对象

之前的版本P层需要持有M层的引用,我们提供了createModel()抽象方法注入M的实例对象。createModel只是创建对象,每次M层的实现类都要覆盖实现这个方法。很繁琐。创建对象的过程能不能抽取封装到基类实现?有经验的或者对java有深入了解的都会想到使用反射可以做。 确实可以。看代码
我们是通过获得泛型类的父类,拿到泛型的接口类实例,所以M层需要有父类接口,因为每个M层都会实现契约类中的IModel接口,所以完全可以使用这种方式。(如果没有可以定义一个IBaseMode的空接口让每个M实现)
BasePresenter 去掉createModel()抽象方法,改用反射方式创建

public abstract class BasePresenter<V, M> {
    //看到很多博客这里使用软引用,其实没必要了,因为我们已经使用detachView 的方式处理了内存泄露问题了。这里看看就行,学习一下软引用的使用方式,没有实际意义
    private SoftReference<V> mViewReference;
    protected V mView;//mProxyView
    protected M mModel;

    protected void attachView(final V view) {
        mViewReference = new SoftReference<V>(view);
//        mView = mViewReference.get();
        //AOP思想,统一做非空判断
        mView = (V) Proxy.newProxyInstance(view.getClass().getClassLoader(), view.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if (mViewReference == null || mViewReference.get() == null) {
                    return null;
                }
                Object object = method.invoke(mViewReference.get(), args);
                return object;
            }
        });

        //通过获得泛型类的父类,拿到泛型的接口类实例,通过反射来实例化 model
        ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass();
        if (type != null) {
            Type[] types = type.getActualTypeArguments();
            try {
                mModel = (M) ((Class<?>) types[1]).newInstance();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }
    }

    protected void detachView() {
        mViewReference.clear();
        mViewReference = null;
        mView = null;
        mModel = null;
    }
}

需要改动的地方P层实现类,不需要LoginPresenter,泛型传入LoginModel 实例类
public class LoginPresenter extends BasePresenter<LoginContract.IView, LoginModel> implements LoginContract.IPresenter {

    @Override
    public void onClickLogin(String username, String pwd) {
        mView.showProgress(true);
        mModel.getUserInfo(username, pwd, new ICallBack<String>() {
            @Override
            public void success(String data) {
                if (mView != null) {
                    mView.showToast("登录成功");
                    mView.showProgress(false);
                    mView.goToMainActivity();
                }
            }

            @Override
            public void error(String error) {
                if (mView != null) {
                    mView.showProgress(false);
                    mView.showToast("登录失败");
                }
            }
        });
    }
}
分析泛型代码如何工作
//通过获得泛型类的父类,拿到泛型的接口类实例,通过反射来实例化 model
        ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass();
        if (type != null) {
            Type[] types = type.getActualTypeArguments();
            try {
                mModel = (M) ((Class<?>) types[1]).newInstance();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }

this.getClass()我们拿到的是 LoginPresenter 类,this.getClass().getGenericSuperclass()获取到 LoginPresenter 的父类 BasePresenter 类。再接着,Type[] types = type.getActualTypeArguments()获取 BasePresenter 的泛型参数,因为这里 LoginModel 是通过 BasePresenter 类的泛型传进去,这里的BasePresenter 有两个泛型参数,它返回一个 Type[] 数组。而第二个就是我们需要的真正的 LoginModel 类对象了,最后通过类对象的 newInstance() 实例化就可以了。

这一小节学习了使用动态代理优化每次需要判空的繁琐问题,使用反射优化创建M层的繁琐代码。下一节学习如何处理 多个P层的问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值