动态代理在MVP中的使用

MVP在Android项目开发中是一种很常用的架构,本文不对MVP的基础概念和基本使用进行叙述,本文要探讨的问题是动态代理在MVP中的应用。

在MVP架构中,P层会持有View,在P层处理完数据后会调用View的方法更新UI。如果View页面关闭了而P中的逻辑还没有执行结束,那么View页面就会出现内存泄漏,不能被GC正常回收,所以在调用View的onCreate方法时会创建Presenter对象并建立二者的绑定关系(为P层的View引用赋值为当前View对象),当调用View的onDestory方法时会解除二者的绑定关系(将P层中的View引用置空),这样才不会导致View内存泄漏。

按照上述逻辑,在View关闭并销毁的时候会将P层中的View引用置空,如果之后P层处理完数据又去调用View的方法,这个时候是会出现空指针异常的,那么就需要在P层中所有调用View方法的地方判断一下View是否为空,这样当需要判断的地方很多的时候,就会感觉很麻烦,并且不容易维护,动态代理就是为了解决这样的问题而引入的,思路就是通过动态代理进行切面拦截来实现统一判空。

下面是在Presenter基类中对以上逻辑进行处理的代码:

package com.znh.commonlib.base;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * Created by znh on 2019/6/3
 * <p>
 * Presenter基类
 */
public class BasePresenter<V extends IBaseView> {

    //实现了IBaseView接口的View及其代理View
    private V mView, mProxyView;

    /**
     * 绑定View
     *
     * @param view
     */
    public void attachView(V view) {
        this.mView = view;
        mProxyView = (V) Proxy.newProxyInstance(view.getClass().getClassLoader(), view.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if (mView == null) {
                    return null;
                }
                return method.invoke(mView, args);
            }
        });
    }

    /**
     * 解绑View
     */
    public void detachView() {
        mView = null;
    }

    /**
     * 对外提供View对象
     *
     * @return
     */
    public V getView() {
        return mProxyView;
    }
}

上述代码中attachView方法是绑定View,在该方法中会为mView赋值,并以mView实现的接口IBaseView为基础创建对应的代理对象。detachView方法是解除绑定View,在该方法中会将mView置空,这样View就不被P层引用了。getView为P层调用View方法提供调用对象,只不过这个调用对象不是真实的View而是代理对象,将对View的调用转嫁到对代理对象的方法调用上,然后在代理对象的方法执行invoke时,在进行判断真实的View是否为空,从而来确定是否执行真实View的方法调用逻辑。

mProxyView是IBaseView接口的一个代理对象,这个对象只具备View层接口定义的所有方法能力,但是这个对象是独立的,它没有View的生命周期和其他内容,所以在P层对View进行解绑的时候,只需要将真实View置空即可,这个代理对象不需要置空也不会造成View内存泄漏(因为这就是一个普通的对象),当需要调用真实View的方法更新UI时,可以替换为调用代理对象mProxyView相对应的方法,然后在代理对象的invoke方法里,判断真实View是否已经不存在了,如果真实View已经onDestory掉了,那就不做处理,如果真实View是存在的,那么就通过method的invoke方法,将真实View和方法参数传递进去,从而达到调用真实View方法的目的(在invoke里将方法的调用偷偷的替换到真实View方法的调用上)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章