MVP
关于MVP模式的总结
- MVP意义
- 简单实现
- 隐藏风险
- 优化
MVP意义
为了解耦合,将页面刷新逻辑和数据加载逻辑区分开来。M->model,进行数据加载;V->view(Activity,Fragment),进行页面业务控制,P->presenter,将M和V结合起来。
V 相当于一台笔记本,如果把音箱、打印机等设备都组装到笔记本上,则显得笔记本比较复杂,体积变大。如果在笔记本上开一个接口,其他设备通过相应数据线(P)连接,那个对于笔记本来说,只要选择要连接的数据线,对于数据线来说,只要选择要连接的设备,对于设备来说,只要做自己的操作,把 数据给数据线,,通过这这种方式,使业务模块化,也更易扩展。MVP 就是这种思想。
MVP简单实现
写View接口
写一个view 接口,包含一个方法,主要用于展示数据,同时写Activity实现此接口,重写showView 方法,在此方法中进行数据刷新加载
public interface BaseMvpView {
public void showView(List<String> list);
}
写model
model,进行数据加载,包含两个部分,加载数据的方法,和加载完成后数据的回调;
public interface BaseMvpMode {
public void getData(GetDataCompleteInterface getDataCompleteInterface);
public interface GetDataCompleteInterface{
public void complete(List<String> list);
}
}
写presenter
presenter,每一个Activity 都应有一个对应的presenter,用于进行数据操作模块的选择和数据的回调展示(连接V和M),包含一个执行方法,调用此方法开始加载数据,重写model的回调接口,实现数据回调,调用View 的方法,实现展示
public class MvpPresenter {
private MvpModel mvpModel;
private MvpView mvpView;
public MvpPresenter(MvpView mvpView){
this.mvpView = mvpView;
mvpModel = new MvpModel();
}
public void LoadingData(){
mvpModel.getData(new BaseMvpMode.GetDataCompleteInterface() {
@Override
public void complete(List<String> list) {
mvpView.showView(list);
}
});
}
}
隐藏风险
空指针
由于页面逻辑和数据加载逻辑分开,当数据加载完成时,如果View已销毁,那么会造成空指针的现象(不该销毁时销毁了)
内存泄露
因为P 中有V 的引用,当V要销毁时,由于未完成加载,P中有V 的引用导致v不能销毁,造成内存泄露(该销毁时没销毁)
解决方法
造成上述两种问题的原因,都是因为P和V 的引用的原因,如果在P 中保存为V 的弱引用,那么问题就可以有效避免,因此要对上述MVP逻辑进行优化。
优化
主要思想是让P 中保存V 的弱引用,由于P 和V 的个数、不定,为了避免重复代码操作,分别抽象P 和 V 的基类,在基类中完成引用的绑定。
- P 基类
1 得到 V 绑定为弱引用
2 提供 V 弱引用
P主要保存引用关系,在基类中将V和P 绑定为弱引用,对于每个继承此基类的P,都能有此操作,避免重复。采用泛型V ,在生成p 时 传过来的V,为V 的实现类,可以正常进行刷新。基类主要做两个操作,绑定引用,提供引用(为保证提供的引用就是当前的V,所以设置V 采用虚方法在子类实现,保证引用为实现类)
public abstract class BaseMvpPresenter <V extends BaseMvpView> {
private WeakReference<V> weakReference;
public void attachView(V baseMvpView){
weakReference = new WeakReference(baseMvpView);
}
public void dettachView(){
if(weakReference!=null){
weakReference.clear();
weakReference = null;
}
}
public V getWeakPerence(){
return weakReference.get();
}
}
- V基类
1 实例化P
2 绑定P 和 V
V基类主要进行 P和V的绑定,需要P实例,由于要绑定的P 实例 不定,因此采用泛型T extents P基类, 又P基类有泛型,需要一个V,因此V基类也要声明出泛型V,传给P基类。对于实例P,因为每个实现类不同,因此P 的 构建应放在实现类中,抽象方法 setBaseMvpPresenter();
public abstract class BaseMvpActivity <V extends BaseMvpView,T extends BaseMvpPresenter<V>>extends AppCompatActivity {
protected T baseMvpPresenter ;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
baseMvpPresenter =setBaseMvpPresenter();
baseMvpPresenter.attachView((V)this);
}
@Override
protected void onDestroy() {
super.onDestroy();
baseMvpPresenter.dettachView();
}
public abstract T setBaseMvpPresenter();
}
V实现类
继承V基类,主要提供V 基类需要的泛型(V ,T),实现虚方法,创建P实例
public class ActivityMvp2 extends BaseMvpActivity <BaseMvpView,MainMvpPresenter>implements BaseMvpView {
private ListView listView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mvp2);
initView();
initData();
}
@Override
public MainMvpPresenter setBaseMvpPresenter() {
return new MainMvpPresenter();
}
private void initData() {
baseMvpPresenter.setModel().loadingData();
}
private void initView() {
listView = (ListView) findViewById(R.id.listview);
}
@Override
public void showView(List<String> list) {
ArrayAdapter adapter = new ArrayAdapter(this,android.R.layout.simple_list_item_1,list);
listView.setAdapter(adapter);
}
}
P实现类
继承P基类,声明P基类需要的泛型V,同时调用基类中保存的 弱引用(getWeakPerence),实现V 的刷新
public class MainMvpPresenter extends BaseMvpPresenter<BaseMvpView>{
BaseMvpMode baseMvpMode;
public MainMvpPresenter(){
}
public MainMvpPresenter setModel(){
baseMvpMode = new MvpModel();
return this;
}
public void loadingData(){
baseMvpMode.loadingData(new BaseMvpMode.LoadCompleteInterface() {
@Override
public void loadComplete(List<String> listData) {
getWeakPerence().showView(listData);
}
});
}
}
小结
基类的编写和泛型的使用,对于P基类 ,因为不知道要绑定的
V引用是什么,因此 使用泛型V 继承基类 V,,
对于 V基类,因为不知道P类型,因此使用泛型P继承基类P,同时要实例化P,但P不定,因此写虚方法,子类实现。