MVP在android中的原理解析 MVP+Retrofit+Rxjava在项目中实战解析 架构经验分享html
MVP是模型(Model)、视图(View)、主持人(Presenter)的缩写,分别表明项目中3个不一样的模块。java
模型(Model):负责处理数据的加载或者存储,好比从网络或本地[数据库]
(lib.csdn.net/base/mysql)…mysql
视图(View):负责界面数据的展现,与用户进行交互;android
以下图所示,sql
这就是MVP模式的整个核心过程。
数据库
上面已经介绍过MVP的核心思想以及基本架构,固然咱们在实际项目中不只仅要把建构划分出来,还要加以延伸,这样才可以使项目的总体架构具有可扩展行、可复用性、可维护性、灵活性。下面我用我在实际项目中的角度来解析我所理解的MVP。编程
/**
* @Description MVP之V层 是全部VIEW的基类,其余类能够继承该类
* @Author ydc
* @CreateDate 2016/10/10
* @Version 1.0
*/
public interface Iview<T> {
/**
* @description 全局的显示加载框
* @author ydc
* @createDate
* @version 1.0
*/
void showLoading();
/**
* @description 全局的显示加载框
* @author ydc
* @createDate
* @version 1.0
*/
...
/**
* @description 当前fragment是否有效
* @author ydc
* @createDate
* @version 1.0
*/
boolean isActive();
}复制代码
能够看出Iview 接口是因此activity 和fragment最基本且共有的方法定义。api
b、NewsView接口代码以下:bash
/**ydc 新闻列表所特有的方法定义
* Created by Administrator on 2017/7/6.
*/
public interface NewsView extends Iview {
void addNews(List<NewsBean> newsList);
void showLoadFailMsg(String msg);
}复制代码
NewsView接口继承自Iview接口,定义新闻列表特有的方法。服务器
c、封装BaseActivity基类
BaseActivity做为因此activity的基类,你能够把因此activity共有的方法和属性提取到该中。复制代码
d、activity_main.xml布局文件代码以下:
布局里面仅仅放了一个RecyclerView,用来展现数据列表。
e、NewListActivity代码以下:
public class NewListActivity extends BaseActivity implements NewsView {
private RecyclerView mRecyclerView;
private LinearLayoutManager mLayoutManager;
private NewsAdapter mAdapter;
private List<NewsBean> mData;
private int pageIndex = 0;
private NewsPresenter mPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPresenter = new NewsPresenter();
mPresenter.attachView(this);
mPresenter.subscribe();
........
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
mAdapter = new NewsAdapter(getApplicationContext());
mRecyclerView.setAdapter(mAdapter);
}
........
@Override
public void addNews(List<NewsBean> newsList) {
mAdapter.isShowFooter(true);
if(mData == null) {
mData = new ArrayList<NewsBean>();
}
mData.addAll(newsList);
if(pageIndex == 0) {
mAdapter.setmDate(mData);
} else {
//若是没有更多数据了,则隐藏footer布局
if(newsList == null || newsList.size() == 0) {
mAdapter.isShowFooter(false);
}
mAdapter.notifyDataSetChanged();
}
}
@Override
public void showLoadFailMsg(String msg) {
}
}复制代码
在NewListActivity 中咱们能够看到,NewListActivity 显示实现了NewsView 接口,实现了NewsView和Iview 未实现的方法,在代码中能够看出NewListActivity并无作一些逻辑处理工做,仅仅作了添加数据和展现数据以及一些提示消息等工做,数据处理的工做都是调用 NewsPresenter 完成的。
二、Presenter层
a、Ipresenter 代码以下:
/**
* @Description MVP的P层
* @Author ydc
* @CreateDate 2016/10/10
* @Version 1.0
*/
public interface Ipresenter<T extends Iview> {
/**
* @description 关联P与V(绑定,VIEW销毁适合解绑)
* @author ydc
* @createDate
* @version 1.0
*/
void attachView(T view);
/**
* @description 取消关联P与V(防止内存泄漏)
* @author ydc
* @createDate
* @version 1.0
*/
void detachView();
/**
* @description RX订阅
* @author ydc
* @createDate
* @version 1.0
*/
void subscribe();
/**
* @description RX取消订阅
* @author ydc
* @createDate
* @version 1.0
*/
void unsubscribe();复制代码
Ipresenter定义了全部presenter最基本且共有的方法。
b、BasePresenter代码以下:
/**
* @Description 抽象的公用Presenter
* @Author ydc
* @CreateDate 20170707
* @Version 1.0
*/
public abstract class BasePresenter<T extends Iview> implements Ipresenter<T> {
protected T mMvpView;//全部View
protected SubscriptionList mSubscriptions;//rx注册中心
protected DataRepository mDataCenter;//数据中心
//protected abstract SubscriptionList createSubscriptionList();//引入darger后取缔
......
/**
* @description p&v没有绑定的异常
* @author ydc
* @createDate
* @version 1.0
*/
public static class MvpViewNotAttachedException extends RuntimeException {
public MvpViewNotAttachedException() {
super("Please call Presenter.attachView(MvpView) before requesting data to the Presenter");
}
}
/**
* @description 统一添加订阅关联被观察者和观察者
* @author ydc
* @createDate
* @version 1.0
*/
public void addSubscription(Observable observable, Subscriber subscriber) {
if( observable!=null && subscriber!=null ){
if (mSubscriptions == null) {
mSubscriptions = new SubscriptionList();
}
mSubscriptions.clear();
mSubscriptions.add(observable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber));
}
}
}复制代码
BasePresenter是一个abstract类,在实现Ipresenter的未实现的方法以外,又扩展了几个因此presenter共用的方法。
c、Presenter代码以下:
/**ydc 新闻类的协议也能够是接口
* Created by Administrator on 2017/7/6.
*/
abstract class Presenter extends BasePresenter<NewsView> {
public abstract void loadNews(int type, int page);
}复制代码
能够看出Presenter也是一个abstract类、继承自BasePresenter抽象类,同时定义了新闻列表所特有的方法。
d、NewsPresenter代码以下:
/**
* Created by Administrator on 2017/7/6.
*/
public class NewsPresenter extends Presenter {
private Model mModel;
public NewsPresenter(){
mModel=new NewsModel();
}
@Override
public void loadNews(int type, int page) {
addSubscription(mModel.loadNews("nc/article/headline/T1348647909107/0-20.html",0), new ApiCallBack<NewsRequestModel>() {
@Override
public void onStart() {
getMvpView().showLoading();
}
@Override
public void onSuccess(NewsRequestModel modelBean) {
if(modelBean!=null){
getMvpView().addNews(modelBean.getT1348647909107());
}
}
@Override
public void onFailure(String errorMsg) {
getMvpView().showLoadFailMsg(errorMsg);
}
@Override
public void onFinished() {
getMvpView().hideLoading();
}
});
}
@Override
public void subscribe() {
}
}复制代码
能够看出NewsPresenter持有view和model的接口或是抽象类,起到中转的做用。
三、Model层
a、Imodel接口代码以下:
**
* @Description MVP的M层
* @Author ydc
* @CreateDate 2016/10/10
* @Version 1.0
*/
public interface Imodel {
}复制代码
我这里其实并无作什么,只是留了一个接口而已,你能够定义因此model的基本方法。
b、BaseModel代码以下:
/**
* @Description 数据模型基础类
* @Author ydc
* @CreateDate 2016/11/2
* @Version 1.0
*/
public abstract class BaseModel implements Imodel {
/**
* @description 返回服务接口对象实例
* @author ydc
* @createDate
* @version 1.0
*/
public <T> T createService(final Class<T> clazz) {
validateServiceInterface(clazz);
return (T) RxService.RETROFIT.createRetrofit().create(clazz);
}
/**
* @description 校验接口合法性
* @author ydc
* @createDate
* @version 1.0
*/
public <T> void validateServiceInterface(Class<T> service) {
if (service == null) {
//AppToast.ShowToast("服务接口不能为空!");
}
if (!service.isInterface()) {
throw new IllegalArgumentException("API declarations must be interfaces.");
}
if (service.getInterfaces().length > 0) {
throw new IllegalArgumentException("API interfaces must not extend other interfaces.");
}
}
}复制代码
这个类我是用它来作Retrofit的初始化以及网络请求的工做,固然我要进一步包装Retrofit,因此这里只看到一个方法调用。
c、Model代码以下:
/**ydc 获取数据的逻辑模块协议,也能够是接口,提供给P调用,在callback中更新V
* Created by Administrator on 2017/7/6.
*/
public abstract class Model extends BaseModel {
public abstract Observable<NewsRequestModel> loadNews(String url, int type);
}复制代码
既然公共BaseModel的职责任命为整个网络调用的工做,那么我就要在抽象一个Model抽象类来定义新闻数据处理逻辑模块协议,提供给P调用。
d、NewsModel代码以下:
/**ydc 新闻数据处理协议
* Created by Administrator on 2017/7/6.
*/
public class NewsModel extends Model {
private INewService service=createService(INewService.class);
@Override
public Observable<NewsRequestModel> loadNews(String url, int type) {
Map<String, String> map = new HashMap<>();
//map.put("type", type+"");
return service.getNewList(url,map);
}
}复制代码
这个类实现了Model做为具体的新闻列表数据处理层。
Retrofit 是 Square 的一个著名的网络请求库,是okHTTP的升级版,目前公认的最好的网络请求框架。
响应式编程RxJava就更不用说,它的强大之处只有用过的人才会体会获得。
Retrofit 除了提供了传统的 Callback 形式的 API,还有 RxJava 版本的 Observable 形式 API。下面我用对比的方式来介绍 Retrofit 的 RxJava 版 API 和传统版本的区别。
以获取一个 User 对象的接口做为例子。使用Retrofit 的传统 API,你能够用这样的方式来定义请求:
@GET("/user")
public void getUser(@Query("userId") String userId, Callback<User> callback);复制代码
在程序的构建过程当中, Retrofit 会把自动把方法实现并生成代码,而后开发者就能够利用下面的方法来获取特定用户并处理响应:
getUser(userId, new Callback<User>() {
@Override
public void success(User user) {
userView.setUser(user);
}
@Override
public void failure(RetrofitError error) {
// Error handling
...
}
};复制代码
其实 Retrofit传统的API调用与okHTTP功能和使用上没有什么本质的区别,它的强大之处在于与RxJava结合使用。
而使用 RxJava 形式的 API,定义一样的请求是这样的:
@GET("/user")
public Observable<User> getUser(@Query("userId") String userId);复制代码
使用的时候是这样的:
getUser(userId)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<User>() {
@Override
public void onNext(User user) {
userView.setUser(user);
}
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable error) {
// Error handling
...
}
});复制代码
看到区别了吗?
当 RxJava 形式的时候,Retrofit 把请求封装进 Observable ,在请求结束后调用 onNext() 或在请求失败后调用 onError()。
对比来看, Callback 形式和 Observable 形式长得不太同样,但本质都差很少,并且在细节上 Observable 形式彷佛还比 Callback 形式要差点。那 Retrofit 为何还要提供 RxJava 的支持呢?
单个请求体现不出它的优点所在,可是情景复杂起来, Callback 形式立刻就会开始让人头疼。
假设 /user 接口并不能直接访问,而须要填入一个在线获取的 token ,代码应该怎么写?
Callback 方式,可使用嵌套的 Callback:
GET("/token")
public void getToken(Callback<String> callback);
@GET("/user")
public void getUser(@Query("token") String token, @Query("userId") String userId, Callback<User> callback);
...
getToken(new Callback<String>() {
@Override
public void success(String token) {
getUser(token, userId, new Callback<User>() {
@Override
public void success(User user) {
userView.setUser(user);
}
@Override
public void failure(RetrofitError error) {
// Error handling
...
}
};
}
@Override
public void failure(RetrofitError error) {
// Error handling
...
}
});复制代码
却是没有什么性能问题,但是迷之缩进并且充满了无穷无尽的回调,这种后果你懂我也懂,作过大项目的人应该更懂。
而使用 RxJava 的话,代码是这样的:
@GET("/token")
public Observable<String> getToken();
@GET("/user")
public Observable<User> getUser(@Query("token") String token, @Query("userId") String userId);
...
getToken()
.flatMap(new Func1<String, Observable<User>>() {
@Override
public Observable<User> onNext(String token) {
return getUser(token, userId);
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<User>() {
@Override
public void onNext(User user) {
userView.setUser(user);
}
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable error) {
// Error handling
...
}
});复制代码
用一个 flatMap() 就搞定了逻辑,整个请求都在一条链当中。读者看到这里应该明白我为何选择RxJava 与 Retrofit 的结合来处理网络请求。其实RxJava有两个比较核心的功能就是数据转换和线程调度,固然它还有其它的强大之处,只是咱们用的最多的是这两个而已。
RxJava 与 Retrofit 的结合在本项目中的应用
一、建立RxService类代:
RxService类主要用来初始化Retrofit以及添加头部和系统参数,NewsModel初始化时,顺带完成了以上工做。
二、INewService接口代码以下:
/**网络接口
* Created by Administrator on 2017/7/6.
*/
public interface INewService {
@GET
Observable<NewsRequestModel> getNewList(@Url String url,
@QueryMap Map<String, String> params);
}复制代码
这个类是来定义新闻列表网络接口
三、管理被观察者和观察者
统一添加订阅关联被观察者和观察者
protected SubscriptionList mSubscriptions;//rx注册中心
/**
* @description 统一添加订阅关联被观察者和观察者
* @author ydc
* @createDate
* @version 1.0
*/
public void addSubscription(Observable observable, Subscriber subscriber) {
if( observable!=null && subscriber!=null ){
if (mSubscriptions == null) {
mSubscriptions = new SubscriptionList();
}
mSubscriptions.clear();
mSubscriptions.add(observable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber));
}
}复制代码
RX取消订阅代码以下:
@Override
public void unsubscribe(){
if(mSubscriptions!=null){
mSubscriptions.clear();
}
}复制代码
以上两段代码是在BasePresenter抽象类中。
四、把请求添加到rx注册中心SubscriptionLis中
public class NewsRequestModel extends BaseFeed {
public List<NewsBean> getT1348647909107() {
return T1348647909107;
}
public void setT1348647909107(List<NewsBean> t1348647909107) {
T1348647909107 = t1348647909107;
}
private List<NewsBean> T1348647909107;
}复制代码
该类继承自BaseFeed,做为新闻列表接口返回实体映射,这个须要和后台api接口开发人员协商好再定义。
做为因此接口返回实体映射基类,这个也须要和后台api开发人员协商好,至少我是这么作的。复制代码
####RxJava 与 Retrofit 的结合小结
Demo如今地址:
[download.csdn.net/download/xi…]
项目地址:
若是你以为此文对您有所帮助,欢迎入群 QQ交流群 :232203809
微信公众号:终端研发部