相关知识和简版架构请参考:
demo地址
本文主要对mvp架构中的一些问题处理,从而完善封装。
1、关于内存泄漏;
说明: 内存泄漏主要原因是生命周期长的持有生命周期短的,导致持有的对象想要回收时无法回收。
场景:
其中mvp架构中,Presenter必须持有View;
Model一般会有异步请求,需要回调结果给Presenter(无论匿名内部类方式还是Presenter实现接口方式),那么Model则必定持有Presenter,同时可能需要使用到Context。
在Model中有耗时操作时就会导致此时Presenter和Context无法回收,而View和Context实际上就是Activity。
解决方法:
使用弱引用,封装在基类中,提供get
和isDestory
方法。每次调用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();
每次调用get时需要判断下
/**
* 请求数据入口
* @param url
*/
@Override
public void requestData(String url) {
if (isViewDestory()) {
return;
}
getMvpView().showLoading();
model.executeGetRequest(url);
}
2、Context的获取方式;
使用接口获取,不要直接传入保存成成员变量,这样符合封闭原则,减少持有而需要防止内存泄漏的处理。
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以实现接口的方式传给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);
}
/**
* 请求数据入口
* @param url
*/
@Override
public void requestData(String url) {
if (isViewDestory()) {
return;
}
getMvpView().showLoading();
model.executeGetRequest(url);
}
如果以匿名内部类的方式实现会直接导致内存泄漏,同时Presenter中代码没那么简洁。
示例:
Presenter中,此时,Model已经隐性强引用了Presenter。
model.loadData(courseId, new HttpResponse<String>(String.class) {
@Override
public void onSuccess(String str) {
}
@Override
public void onError(final String msg) {
}
});