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

Posted 0 and 1

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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层的问题。

以上是关于Android MVP-编程思想4(AOP思想-动态代理运用,反射创建M层实例对象)的主要内容,如果未能解决你的问题,请参考以下文章

Android MVP-编程思想1(什么是MVC-MVP-MVVM模式?)

Android MVP-编程思想5(如何处理多个P层的问题?)

Android MVP-编程思想5(如何处理多个P层的问题?)

Android MVP-编程思想3(MVP-内存泄露问题处理,基类封装,有没有必要再使用软引用?)

Android MVP-编程思想6(依赖注入多个P层方式优化---注解,反射)

Android MVP-编程思想6(依赖注入多个P层方式优化---注解,反射)