相關(guān)知識和簡版架構(gòu)請參考:
【Android】mvp架構(gòu)模式知識匯總 - 簡書
demo地址
本文主要對mvp架構(gòu)中的一些問題處理,從而完善封裝。
1、關(guān)于內(nèi)存泄漏;
說明: 內(nèi)存泄漏主要原因是生命周期長的持有生命周期短的,導致持有的對象想要回收時無法回收。
場景:
其中mvp架構(gòu)中,Presenter必須持有View;
Model一般會有異步請求,需要回調(diào)結(jié)果給Presenter(無論匿名內(nèi)部類方式還是Presenter實現(xiàn)接口方式),那么Model則必定持有Presenter,同時可能需要使用到Context。
在Model中有耗時操作時就會導致此時Presenter和Context無法回收,而View和Context實際上就是Activity。
解決方法:
使用弱引用,封裝在基類中,提供get和isDestory方法。每次調(diào)用get前需要先判斷下
示例:BasePresenter中
/**
* View是否有被回收
*
* @return
*/
public boolean isViewDestory() {
if (iViewWeakRef == null) {
return true;
}
V view = iViewWeakRef.get();
if (view == null) {
return true;
}
if (view instanceof Activity) {
Activity activity = (Activity) view;
if (activity.isDestroyed() || activity.isFinishing()) {
return true;
}
}
return false;
}
/**
* 與view解綁
*/
public void detachView() {
if (iViewWeakRef != null) {
iViewWeakRef.clear();
}
iViewWeakRef = null;
model.destory();
}
BaseView中
Context getContext();
BaseCallBack中
Context getContext();
每次調(diào)用get時需要判斷下
/**
* 請求數(shù)據(jù)入口
* @param url
*/
@Override
public void requestData(String url) {
if (isViewDestory()) {
return;
}
getMvpView().showLoading();
model.executeGetRequest(url);
}
2、Context的獲取方式;
使用接口獲取,不要直接傳入保存成成員變量,這樣符合封閉原則,減少持有而需要防止內(nèi)存泄漏的處理。
BaseView中
Context getContext();
BaseCallBack中
Context getContext();
如果使用傳入的方式則是
/**
* 綁定mvp的View接口
*
* @param cxt
* @param mvpView
*/
public void attachView(Context cxt, V mvpView) {
this.mContext = cxt;
this.iView = mvpView;
}
這樣同時需要維護mContext、iView兩個變量。
3、Presenter與Model交互方式;
Presenter以實現(xiàn)接口的方式傳給Model,這樣可以Presenter中代碼更簡潔,還可以讓Model弱引用持有Presenter,并且通過接口方式獲取Context,不用再次傳入。
示例:
BaseModel中
public abstract class BaseModel<I extends BaseCallBack> {
protected WeakReference<I> iCallBackWeakRef;
public BaseModel(I iCallBack) {
iCallBackWeakRef = new WeakReference<>(iCallBack);
}
Presenter中
@Override
protected StudentModel createModel(BasePresenter presenter) {
return new StudentModel(this);
}
/**
* 請求數(shù)據(jù)入口
* @param url
*/
@Override
public void requestData(String url) {
if (isViewDestory()) {
return;
}
getMvpView().showLoading();
model.executeGetRequest(url);
}
如果以匿名內(nèi)部類的方式實現(xiàn)會直接導致內(nèi)存泄漏,同時Presenter中代碼沒那么簡潔。
示例:
Presenter中,此時,Model已經(jīng)隱性強引用了Presenter。
model.loadData(courseId, new HttpResponse<String>(String.class) {
@Override
public void onSuccess(String str) {
}
@Override
public void onError(final String msg) {
}
});