使用泛型,動態代理優化 mvp

解決問題

  1. Model 獲取到數據之前,退出了 Activity,此時由於 Activity 被 Presenter 引用,而 Presenter 正在進行耗時操作,會導致 Activity 的對象無法被回收,造成了內存泄漏

通過在 BaseActivity 中重寫onDestroy 來解綁presenter

  @Override
    protected void onDestroy() {
        super.onDestroy();
        //解綁Presenter
        presenter.detach();
    }
presenter
  /**
     * 解綁View
     */
    public void detach() {
        mView = null;
        mModel = null;
    }

這個時候帶來的問題就是 Model 獲取到數據之後調用 mView接口方法會空指針,所以做出優化

可以通過判斷 mview 是否爲空來解決,通過學習 retrofit的源碼之後發現可以類似 ServiceMethod的創建使用動態代理來優化

public class BasePresenter<V extends BaseView, M extends BaseModel> {
    private V mView;
    private M mModel;

    /**
     * 綁定View
     *
     * @param view
     */
    public void attach(final V view) {
        //動態代理
        mView = (V) Proxy.newProxyInstance(view.getClass().getClassLoader(), view.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //在View層顯示數據之前用戶可能退出了View層的頁面,會在Activity的onDestroy()方法中會把mView置爲null
                //由於View層都是接口,這裏採用了動態代理,如果在View層顯示數據之前用戶可能退出了View層的頁面,返回null的話,onSuccess()方法不會執行
                if (mView == null) {
                    return null;
                }
                //每次調用View層接口的方法,都會執行這裏
                return method.invoke(view, args);
            }
        });
        //用反射動態創建Model
        Type[] params = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments();
        try {

            mModel = (M) ((Class) params[1]).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * 解綁View
     */
    public void detach() {
        mView = null;
        mModel = null;
    }

    public V getView() {
        return mView;
    }

    public M getModel() {
        return mModel;
    }
}

  1. 單 View 多 Presenter 的優化

通過反射創建Presenter ,類似功能在 學習的 demo 項目中使用 模仿 xutils 來動態注入控件省去 findbyid

 @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getLayoutId());
        mPresenters = new ArrayList<>();
        //1 Activity ? ViewGroupMvpProxy ? Fragment?抽離 工具類抽出去,或者把每個代碼copy
        //注入Presenter 通過反射(或者Dagger)
        Field[] fields = this.getClass().getDeclaredFields();
        for (Field field : fields) {
            InjectPresenter injectPresenter = field.getAnnotation(InjectPresenter.class);
            if (injectPresenter != null) {
                //創建注入
                Class<? extends BasePresenter> presenterClazz = null;
                try {
                    //獲取這個類
                    presenterClazz = ( Class<? extends BasePresenter> ) field.getType();
                } catch (Exception e) {
                    throw new RuntimeException("not support inject presenter" + field.getType());
                }
                try {
                    //創建BasePresenter對象
                    BasePresenter basePresenter = presenterClazz.newInstance();
                    //attach
                    basePresenter.attach(this);
                    mPresenters.add(basePresenter);
                    field.setAccessible(true);
                    field.set(this, basePresenter);
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        initView();
        initData();
    }

測試用數據,可通過 charles 攔截返回

{
  "code": "200",
  "data": {
    "userName": "zhoubk",
    "userSex": "man",
    "id": 1
  },
  "msg": "success"
}

完整項目代碼 github

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