解決問題
- 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;
}
}
- 單 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