一个简单的MVP Demo

来源:互联网 发布:希捷数据恢复软件 编辑:程序博客网 时间:2024/05/22 03:09
  • MVP是当下比较流行的框架,相对与mvc框架,他可以将View层和model层完全解耦,是代码的阅读和维护更加清晰明朗。

  • 这里主要介绍一种mvp的实现方式,主要的类图如下。

MVP主要类图

这个框架的好处是在与将Persenter层对于View(Activity)层的引用,使用弱引用。避免了Model层在做耗时操作时,如果用户点击了返回,退出当前页面时,可以将view层与persenter的引用断开,避免activity层的内存泄漏。
代码地址:https://github.com/Lilee902/Mvp

Base层代码部分

主要的设计部分上base层的baseView和BaseMVPActivtiy和BasePersenter。

  • 先从最简单的BaseView开始,这个view将会被Activity实现,并传递给persenter持有,用于p层和view层通信。
public interface BaseView {}
  • 然后是BasePersenter层。这个类的声明需要指定一个泛型,具体好处再往下面阅读。
public abstract class BasePersenter<T extends BaseView> {}
  • 声明BaseMvpActivity ,这个类的声明,主要是泛型的,其中V表示BaseView的继承类,P表示BasePersenter的继承类。
public abstract class BaseMVPActivity<V extends BaseView, P extends BasePersenter<V>>            extends AppCompatActivity implements BaseView {}
  • MVP的设计在于,让view层和model层的引用隔离开,不再相互持有。而view层将要做的事情传给中间层P层,P层再传给model层去做处理。我们现在要做的是P层与View层的持有做成弱引用,方便gc回收。
public abstract class BaseMVPActivity<V extends BaseView, P extends BasePersenter<V>>        extends AppCompatActivity implements BaseView {    // Persenter类的实例。    public P mActPersenter;    @SuppressWarnings("unchecked")    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        mActPersenter = createPersenter();        if (mActPersenter != null) {            // BasePersenter类的方法。主要用于将View用弱引用赋值给P层的View对象            mActPersenter.attach((V) this);        }    }    // 子类实现,具体类型创建具体P层对象。    protected abstract P createPersenter();    @Override    protected void onDestroy() {        if (mActPersenter != null) {            // BasePersenter类的方法。主要用于将View的引用清除。            mActPersenter.detach();        }        super.onDestroy();    }}
  • 从上面的代码可以看到,在activity的oncreate和ondestory方法中,调用了Persenter的attach和detach方法。这两个方法的作用就是将View对象传给p层持有。而具体的P对象,则是通过抽象方法,让子类具体去创建。
  • 那么P层的attach和detach又是如何实现的呢?我们来具体看一下:
public abstract class BasePersenter<T extends BaseView> {    // 弱引用的View    public WeakReference<T> mActView;    public BasePersenter() {        super();    }    // 获取View中view引用。    protected T getView() {        return mActView.get();    }    // 判断view的引用是否仍持有,没有被GC回收。    public boolean isViewAttached() {        return mActView != null && mActView.get() != null;    }    // 将View对象以若引用的形式给mActView持有。    public void attach(T view) {        if (mActView == null) {            mActView = new WeakReference<T>(view);        }    }    // 将View在Activity调用onDestory时,释放。以便于Activiy销毁掉之后,内存可以被正常回收。    public void detach() {        if (mActView != null) {            mActView.clear();            mActView = null;        }    }}
  • 上面是BasePersenter类的所有代码。可以看到attach 就是将View用一个弱引用保存起来(这里也有用软引用的,具体可以再在项目中实测决定,弱引用和软引用gc的回收的条件有差异)。而detach则是将View层和p层的引用断开,方便view层被回收。
  • isViewAttached方法,是用来判断当前的引用是否已经被gc回收,如果回收则表明View层已经走了ondestory方法,销毁掉了,就没有必要调用刷新UI线程的方法了。
  • getView方法是返回View对象。

具体使用

使用起来还是比较简单的。下面我简单贴一下几个主要的类,也可以进入github看具体代码。
代码地址:https://github.com/BravoLee/Mvp

  • Activity类
public class MainActivity extends BaseMVPActivity<MainView, MainPersenter> implements View.OnClickListener, MainView {    private static final String TAG = MainActivity.class.getSimpleName();    private ActivityMainBinding mainBinding;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        mainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);        initEvent();    }    private void initEvent() {        mainBinding.btnChange.setOnClickListener(this);    }    @Override    protected MainPersenter createPersenter() {        return new MainPersenter();    }    @Override    public void onClick(View view) {        switch (view.getId()) {            case R.id.btn_change:                mActPersenter.doAdd();                break;        }    }    @Override    public int getTvNumber() {        String intStr = mainBinding.tvNumber.getText().toString().trim();        return Integer.parseInt(intStr);    }    @Override    public void setTvNumber(String s) {        mainBinding.tvNumber.setText(s);    }}
  • Persenter层
import com.bravo.mvp.base.BasePersenter;/** * Created by Administrator on 2017/8/7. */public class MainPersenter extends BasePersenter<MainView> implements ModuleListener {    private final MainModule mainModule;    public MainPersenter() {        mainModule = new MainModuleImp(this);    }    public void doAdd() {        int number = getNowNumber();        mainModule.doAdd(number);    }    private int getNowNumber() {        if (isViewAttached()) {            return mActView.get().getTvNumber();        }        return -1;    }    @Override    public void addFinish(int i) {        if (isViewAttached()){            mActView.get().setTvNumber(String.valueOf(i));        }    }    @Override    public void onAddError(Exception e) {        if (isViewAttached()){            mActView.get().onRespondError(e.getMessage());            mActView.get().setTvNumber("0");        }    }}
  • model层 模拟网络访问,有成功和失败两种情况。
public class MainModuleImp implements MainModule {    private ModuleListener listener;    public MainModuleImp(ModuleListener listener) {        this.listener = listener;    }    @Override    public void doAdd(int number) {        if (number >= 0 && number < 10) {            listener.addFinish(++number);        } else {            listener.onAddError(new Exception("Number can not be a minus or bigger than 10 !"));        }    }}

缺点

  • mvp架构会让类和接口增多
  • 上面介绍的这种方法的话,每个activity对应一个view接口用于刷新Activity的UI,这样的话,违反了接口单一原则。

优点

  • 可以将具体的业务实现放在Persenter层和model层,activity层只负责UI的展示,要做什么事情传给Persenter和model层去做,这样后面在代码阅读和维护上会清晰很多。还是很值得引入的。

Github上面优秀的mvp框架

  • TheMvp : https://github.com/kymjs/TheMVP
  • Nucleus : https://github.com/konmik/nucleus
  • Beam : https://github.com/Jude95/Beam
原创粉丝点击