一个简单的MVP Demo
来源:互联网 发布:希捷数据恢复软件 编辑:程序博客网 时间:2024/05/22 03:09
MVP是当下比较流行的框架,相对与mvc框架,他可以将View层和model层完全解耦,是代码的阅读和维护更加清晰明朗。
这里主要介绍一种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
阅读全文
1 0
- 一个简单的MVP Demo
- MVP简单demo
- 初识MVP,简单Demo
- 这是一个使用mvp模式实现模拟用户登录的简单Demo。
- 一个简单的MVP模式
- 一个demo理解什么是MVP
- 一个登录Demo初识MVP
- 一个简单的MVP小例子
- MVP 一个简单的登录+判断
- 一个简单的Flex Demo
- 一个简单的触发器(Demo)
- 一个简单的Gephi Demo
- 一个简单的缓存Demo
- 一个简单的广播Demo
- Lucene5 一个简单的Demo
- 一个简单的ReactNative demo
- WebSocket -- 一个简单的Demo
- 一个简单的线程demo
- Overriding与Overloading
- Spring和SpringMVC的包扫描问题
- excel链接mysql
- Python os模块
- Android性能优化之延迟加载视图
- 一个简单的MVP Demo
- uva 766 sum of power
- 软件测试知识
- (三)字典
- 无偿地给NoBook仿真实验教学工具打个友情广告,真心点赞,NB!
- vue cli巨坑亲历
- 聚簇索引与非聚簇索引的区别
- 【精华版】MyBatis生成逆向工程
- 常用排序算法总结(一)