Android MVP架构模式举例_Android中 MVP框架原理理解
2020-09-02 13:48:08 By: shinyuu
在Android项目中,按照MVC的分层,Activity和Fragment应该属于View层,用于展示UI界面,以及接收用户的输入,此外还要承担一些生命周期的工作。所以开发的时候我们经常把一些业务逻辑直接写在Activity里面,这非常直观方便,代价就是Activity会越来越臃肿,而在Activity中,把View和Controller抽离开来,而这就是MVP模式的工作了。
MVP模式的核心思想
MVP把Activity中的UI逻辑抽象成View接口,把业务逻辑抽象成Presenter接口,Model类还是原来的Model。这就是MVP模式,现在这样的话,Activity的工作的简单了,只用来响应生命周期,其他工作都丢到Presenter中去完成。从上图可以看出,Presenter是Model和View之间的桥梁,为了让结构变得更加简单,View并不能直接对Model进行操作,这也是MVP与MVC最大的不同之处。
MVP模式的作用
- 分离了视图逻辑和业务逻辑,降低了耦合
- Activity只处理生命周期的任务,代码变得更加简洁
- 视图逻辑和业务逻辑分别抽象到了View和Presenter的接口中去,提高代码的可阅读性
- Presenter被抽象成接口,可以有多种具体的实现,所以方便进行单元测试
- 把业务逻辑抽到Presenter中去,避免后台线程引用着Activity导致Activity的资源无法被系统回收从而引起内存泄露和OOM
应用举例
在这里使用一个在ListView中更新适配器数据的例子来简单说明MVP模式是怎么使用的。
1.项目结构
在这里,颜色标注的即是我们用到的
2. model层
使用的是GsonFormat插件自动生成的bean,因此model层不需要关注bean,但由于使用了Retrofit Rxjava。
PS:使用Retrofit是因为可以很简单处理异步请求,而使用Rxjava是因为可以将被观察者跟观察者的调度任务自动切换io跟ui线程。 因此,在model层,只需要关心manager怎么组织即可。
public class DataManager { private RetrofitService mRetrofitService; public DataManager(){ this.mRetrofitService = RetrofitHelper.getInstance() .getRetrofit("http://api.douban.com/v2/").getServer(); } public Observable<Douban> getDoubanInfo(){ return mRetrofitService.getInTheaters(); } }
3. present层
present就是用来处理所有业务逻辑工作的代理层,假设我们在Activity/Fragment中可以把工作丢给present来处理,那会有哪些方法呢?
更新上映电影的数据
提供页面跳转时的方法 于是就有了IDoubanPresenter这个接口
public interface IDoubanPresenter { void updateInTheaters(); void reachDetail(); }
那么它的实现则为
public class DoubanPresenter implements IDoubanPresenter { private DataManager dataManager; private CompositeSubscription mCompositeSubscription; private IDoubanView mIDoubanView; private int index; public Douban mDouban; public DoubanPresenter (IDoubanView view){ this.mIDoubanView = view; dataManager = new DataManager(); mCompositeSubscription = new CompositeSubscription(); } public void onStop() { if (mCompositeSubscription.hasSubscriptions()){ mCompositeSubscription.unsubscribe(); } } @Override public void updateInTheaters(){ mCompositeSubscription.add(dataManager.getDoubanInfo() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<Douban>(){ @Override public void onCompleted() { if (mDouban != null){ mIDoubanView.updateInTheaters(mDouban); } } @Override public void onError(Throwable e) { e.printStackTrace(); } @Override public void onNext(Douban douban) { mDouban = douban; } }) ); } @Override public void reachDetail(){ mCompositeSubscription.add(dataManager.getDoubanInfo() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<Douban>(){ @Override public void onCompleted() { if (mDouban != null){ mIDoubanView.enterDetail(mDouban, index); } } @Override public void onError(Throwable e) { e.printStackTrace(); } @Override public void onNext(Douban douban) { mDouban = douban; } }) ); } }
在Present中可以看到,我们持有dataManager跟view的实例,因为业务逻辑都在这里处理,dataManager用来处理数据很好理解,view在这里不做真正的操作,只是执行一个接口方法,剩下的在接口实现里完成。
4. view层
view层其实就是我们的Activity或者Fragment。在使用List更新豆瓣接口数据,UI操作需要的方法有
- 更新上映电影的View
- 页面跳转时的方法
- 异常时怎么显示 于是就有了IDoubanView这个接口
public interface IDoubanView { void updateInTheaters(Douban mDouban); void enterDetail(Douban mDouban, int index); void onError(String result); }
然后我们在Fragment中实现这个接口
public class DoubanFragment extends Fragment implements IDoubanView { private ListView listView; private DoubanItemAdapter mAdapter; private DoubanPresenter mDoubanPresenter; @Nullable @Override public View onCreateView(@NonNull final LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.card_fragment, container, false); listView = view.findViewById(R.id.card_listview); mDoubanPresenter = new DoubanPresenter(this); mDoubanPresenter.updateInTheaters(); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { mDoubanPresenter.reachDetail(); } }); return view; } @Override public void updateInTheaters(Douban mDouban) { mAdapter = new DoubanItemAdapter(getActivity(), mDouban.getSubjects()); listView.setAdapter(mAdapter); mAdapter.notifyDataSetChanged(); } @Override public void enterDetail(Douban mDouban, int index) { Intent mIntent = new Intent(getActivity(), WebActivity.class); mIntent.putExtra("url", mDouban.getSubjects().get(index).getAlt()); startActivity(mIntent); } @Override public void onError(String result) { } }
其中updateInTheaters跟enterDetail这两个接口方法由prisent调用实现。所以这个链路变成Activity/Fragment(移交任务) -> Present(数据处理) -> Activity/Fragment(渲染view)。
在家赚钱 2020-09-08 21:15:21 1 评 | 回复
已阅,感谢站长分享!