MVP在Android项目中的简单体现
2017-02-08 15:37
471 查看
通过简单案例来说明MVP的使用,retrofit2+rxjava+mvp
项目地址:http://www.github.com/jjdxmashl/jjdxm_demomvp
Model 一部分是处理业务逻辑,一部分是提供View显示的数据。
View 代表的是一个接口,一个将UI界面提炼而抽象出来的接口。
Presenter Model和View之间的桥梁
按照模块分包
按照功能分包
如图
主程序app module中build.gradle的第二行添加,用于注解
dependencies节点中添加
如图
清单文件AndroidManifest.xml中,添加权限
网络接口请求服务类
网络接口请求基类
网络接口请求工具类
如图
UI界面抽象出来的接口
业务逻辑实现的基类
连接Model和View的桥梁的基类
persenter和activity绑定
最后是Activity的基类
MVP的Activity基类
编译运行效果图如下
同理笑话大全也一样的创建对应的文件,最后运行如下
项目地址:http://www.github.com/jjdxmashl/jjdxm_demomvp
项目地址:http://www.github.com/jjdxmashl/jjdxm_demomvp
前言
什么是MVP?
MVP模式是一种架构模式,也是一种经典的界面模式。MVP中的M代表Model, V是View, P是Presenter。Model 一部分是处理业务逻辑,一部分是提供View显示的数据。
View 代表的是一个接口,一个将UI界面提炼而抽象出来的接口。
Presenter Model和View之间的桥梁
MVP在Android项目中的其中一种体现方式
经过查阅网上一些MVP的文章之后,有部分案例在presenter中实现具体的逻辑或者把Model单纯的看作是具体的Bean,个人觉得是不太准确的,MVX(MVC、MVP和MVVM)中,M的职责都应该包含两部分业务逻辑和提供View显示的数据,而X的部分则是为了实现UI界面和业务逻辑解耦的桥梁,在Android项目中使用MVP架构模式,以下这两种架构方式是我比较能接受和认可的。按照模块分包
|----包名 | |----base | | BaseActivity Activity基类 | | BaseMVPActivity MVP Activity基类 | | BaseModel Model基类 | | BaseFragment Fragment基类 | | IBaseDelegate 简化Presenter在Activity的实现 | | IBasePresenter Presenter基类 | | IBaseView View基类 | |----模块名1 | | |----model 业务逻辑和bean | | | xxxModel | | | xxxBean | | |----presenter 连接View和Model的桥梁 | | | xxxPresenter | | |----ui UI界面相关的类 | | | xxxActivity | | | xxxFragment | | |----view UI界面提炼出来的接口 | | | xxxView | |----模块名2
按照功能分包
|----包名 | |----activity 具体Activity | | xxxActivity | |----adapter 具体Adapter | | xxxAdapter | |----base | | BaseActivity Activity基类 | | BaseMVPActivity MVP Activity基类 | | BaseModel Model基类 | | BaseFragment Fragment基类 | | IBaseDelegate 简化Presenter在Activity的实现 | | IBasePresenter Presenter基类 | | IBaseView View基类 | |----fragment 具体Fragment | | xxxFragment | |----hodler 具体Holder | | xxxHodler | |----model 业务逻辑和bean | | xxxModel | | xxxBean | |----presenter 连接View和Model的桥梁 | | xxxPresenter | |----view UI界面提炼出来的接口 | | xxxView | |----widget
前期准备
这里使用聚合数据提供的免费API来实现两个具体的功能历史上的今天和笑话大全,注册并实名为聚合数据的用户后,生成属于自己的用户key即可。快速开始
step1 添加所需的依赖和权限
新建一个项目,在根目录的build.gradle的dependencies节点中添加,用于注解classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
如图
主程序app module中build.gradle的第二行添加,用于注解
apply plugin: 'com.neenbedankt.android-apt'
dependencies节点中添加
compile 'com.android.support:appcompat-v7:24.2.1' compile 'com.android.support:design:24.2.1' //布局注解 apt 'com.jakewharton:butterknife-compiler:8.0.1' compile 'com.jakewharton:butterknife:8.0.1' //响应式编程 compile 'io.reactivex:rxandroid:1.1.0' compile 'io.reactivex:rxjava:1.1.0' //联网类库 compile 'com.squareup.retrofit2:retrofit:2.1.0' compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0' compile 'com.squareup.retrofit2:converter-scalars:2.1.0' compile 'com.dou361.retrofit2:jjdxm-retrofit-converter-fastjson:1.0.0' compile 'com.squareup.okhttp3:okhttp:3.3.0' //自定义view compile 'com.dou361.customui:jjdxm-customui:1.0.9' //recyclerview基类 compile('com.dou361.recyclerview:jjdxm-recyclerview:1.0.2') { exclude group: 'com.android.support', module: 'design' }
如图
清单文件AndroidManifest.xml中,添加权限
<uses-permission android:name="android.permission.INTERNET"/>
step2
先写好两个网络请求方法,Observable searchHistory(String month, String day)和Observable loadJoke(String page)分别是查询历史今天方法和加载笑话列表网络接口请求服务类
public interface IApiService { /** 查询历史的今天 */ @GET("/japi/toh") Observable<RepoHistory> searchHistory(@QueryMap Map<String, String> map); /** 加载笑话列表 */ @GET("/joke/content/list.from") Observable<RepoJoke> loadJoke(@QueryMap Map<String, String> map); }
网络接口请求基类
public class ApiBase { /**历史上的今天 http://api.juheapi.com/japi/toh?key=7ac7e02ff7f1f8f1ccdc2f9e5dddb6be&v=1 * .0&month=11&day=1*/ /** 笑话大全 http://japi.juhe.cn/joke/content/list * .from?key=d796a03545bddee0b56d913111f5f199&page=2&pagesize=10&sort=asc&time=1418745237 */ protected static IApiService getService() { return getService(null); } protected static IApiService getService(String ip) { return getService(ip, 0, 0); } protected static IApiService getService(String ip, long readTime, long connectTime) { OkHttpClient client = new OkHttpClient.Builder() .readTimeout(readTime <= 0 ? 30 : readTime, TimeUnit.SECONDS) .connectTimeout(connectTime <= 0 ? 30 : connectTime, TimeUnit.SECONDS) .build(); Retrofit retrofit = new Retrofit.Builder() .baseUrl(ip == null ? "http://api.juheapi.com" : ip) .client(client) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addConverterFactory(ScalarsConverterFactory.create()) .addConverterFactory(FastJsonConverterFactory.create()) .build(); return retrofit.create(IApiService.class); } }
网络接口请求工具类
public class ApiUtils extends ApiBase { public static Observable<RepoHistory> searchHistory(String month, String day) { /**key=7ac7e02ff7f1f8f1ccdc2f9e5dddb6be&v=1.0&month=11&day=1*/ Map<String, String> map = new HashMap<>(); map.put("key", "7ac7e02ff7f1f8f1ccdc2f9e5dddb6be"); map.put("v", "1.0"); map.put("month", month); map.put("day", day); return getService().searchHistory(map); } public static Observable<RepoJoke> loadJoke(String page) { /**key=d796a03545bddee0b56d913111f5f199&page=2&pagesize=10&sort=asc&time=1418745237*/ Map<String, String> map = new HashMap<>(); map.put("key", "d796a03545bddee0b56d913111f5f199"); map.put("sort", "asc"); map.put("time", "1418745237"); map.put("page", page); map.put("pagesize", "10"); return getService().loadJoke(map); } }
如图
step3
开始架构MVP模式使用到的基类,这里没有使用网上所说的契约类xxxContract把View和Presenter写在一个类中维护,而是分开出来,主要看个人喜好,如图UI界面抽象出来的接口
public interface IBaseView { /** * 显示加载 */ void showLoading(); /** * 完成加载 */ void dismiss(); }
业务逻辑实现的基类
public abstract class BaseModel<SubP> { protected SubP mPresenter; public BaseModel(SubP presenter) { this.mPresenter = presenter; } }
连接Model和View的桥梁的基类
public interface IBasePresenter<V extends IBaseView> { /**绑定接口*/ void attachView(V view); /**释放接口*/ void detachView(); }
persenter和activity绑定
public interface IBaseDelegate<V extends IBaseView, P extends IBasePresenter<V>> { /**初始化presenter*/ @NonNull P createPresenter(); /**获取presenter*/ @NonNull P getPresenter(); }
最后是Activity的基类
public abstract class BaseActivity extends AppCompatActivity { protected void startActivity(Class<?> clz) { Intent intent = new Intent(this, clz); startActivity(intent); } }
MVP的Activity基类
public abstract class BaseMVPActivity<V extends IBaseView, P extends IBasePresenter<V>> extends BaseActivity implements IBaseDelegate<V, P> { protected P mPresenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mPresenter = createPresenter(); } @NonNull @Override public P getPresenter() { return mPresenter; } @Override protected void onDestroy() { mPresenter.detachView(); super.onDestroy(); } }
step4
针对模块用MVP模式去架构大概有一下4个步骤步骤1:UI实现View方法,引用Presenter 步骤2:Presenter调用Model,走Model具体逻辑 步骤3:Model逻辑实现,回调Presenter方法 步骤4:Presenter回调View,即回到UI,回调View方法
step5
具体模块功能的实现,历史的今天模块,先创建一个HistoryActivity继承BaseMVPActivity,新建IHistoryView并实现。1.View的接口的抽取
抽象出来三个功能和父类IBaseView的两个方法,分别是显示加载好的数据,显示空白数据提示,检测数据提示,显示加载中提示,隐藏加载中提示。public interface IHistoryView extends IBaseView { /**显示数据*/ void showData(List<HistoryBean> list); /**无数据*/ void showEmpty(); /**检测数据*/ void showMessage(String msg); }
2.Model的实现
具体的逻辑实现,这里只有一个方法就是查询历史今天public class HistoryModel extends BaseModel<HistoryPresenter> { public HistoryModel(HistoryPresenter presenter) { super(presenter); } public void searchHistory(String month, String day) { if (TextUtils.isEmpty(month)) { mIPresenter.showMessage("月份不能为空"); return; } int iMonth = Integer.valueOf(month).intValue(); if (iMonth <= 0 || iMonth > 12) { mIPresenter.showMessage("只能输入1-12的月份"); return; } if (TextUtils.isEmpty(day)) { mIPresenter.showMessage("天不能为空"); return; } int iDay = Integer.valueOf(day).intValue(); if (iDay <= 0 || iDay > 31) { mIPresenter.showMessage("只能输入1-31的天"); return; } ApiUtils.searchHistory(month, day) .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.newThread()) .subscribe(new Action1<RepoHistory>() { @Override public void call(RepoHistory repoHistory) { if (repoHistory == null || repoHistory.getResult() == null || repoHistory.getResult().size() <= 0) { mIPresenter.showEmpty(); } else { mIPresenter.showData(repoHistory.getResult()); } } }); } }
3.Presenter桥梁的实现
public class HistoryPresenter implements IBasePresenter<IHistoryView> { private IHistoryView mView; private HistoryModel mModel; public HistoryPresenter(IHistoryView view) { attachView(view); mModel = new HistoryModel(this); } @Override public void attachView(IHistoryView view) { this.mView = view; } @Override public void detachView() { this.mView = null; } public void showData(List<HistoryBean> list) { mView.dismiss(); mView.showData(list); } public void showEmpty() { mView.dismiss(); mView.showEmpty(); } public void showMessage(String msg) { mView.showMessage(msg); } public void searchHistory(String month, String day) { mView.showLoading(); mModel.searchHistory(month, day); } }
4.最后在HistoryActivity里面去建立连接
最后创建的类架构图如下:编译运行效果图如下
同理笑话大全也一样的创建对应的文件,最后运行如下
项目地址:http://www.github.com/jjdxmashl/jjdxm_demomvp
相关文章推荐
- 【知识必备】浅淡MVP在Android项目中的实战演习,让代码结构更简单~
- RxJava+Retrofit+OkHttp3+Dagger2+MVP构建Android项目简单例子
- 基于MVP开发模式的简单Android项目
- 【知识必备】浅淡MVP在Android项目中的实战演习,让代码结构更简单~
- 移动架构42_Android项目中MVP简单实现
- Android应用开发高效工具集1---ant构建简单Android项目
- Android应用开发高效工具集1---ant构建简单Android项目
- 在window下,简单利用NDK编译c/c++文件,在android项目中调用。
- 【P000-000】第一个项目,暂定为android手机上的简单证券交易费计算系统(附1.0源码)
- 二、东软实践项目2-基于android平台的应用开发:简单用户登陆
- Android视频播放项目总结之 适配器绑定视频信息列表显示到界面(适配器简单优化)
- Android应用开发高效工具集1---ant构建简单Android项目
- Eclipse配合ADT为Android项目添加Proguard混淆的简单新方法
- 学习Android开源项目-根据知乎日报API分析重构一个简单的知乎日报Android客户端
- linux下eclipse构建并编译android一个简单jni项目
- android-async-http开源项目的GET方式或POST方式实现登陆案例简单Demo
- android中MVP模式--此模式可以更简单地测试
- android_项目_知识积累_mina通信(java程序简单通信)
- 用Eclipse+Cygwin+CDT+NDK来创建一个简单的Android JNI 项目
- 【P000-000】第一个项目,暂定为android手机上的简单证券交易费计算系统(源码列表统一在此更新)