MVP模式入门(结合Rxjava,Retrofit)
本文MVP的sample实现效果:
github地址:https://github.com/xurui1995/MvpSample
老规矩,在说对MVP模式的理解之前还是要再谈谈MVC模式,了解了MVC的缺点。我们才知道为什么要用MVP。
关于MVC的图解,我在网上找到了一些图。如下:
MVC模式在开发web或者管理系统中应用很多,我们的View与人交互,人点击鼠标或者输入一些东西时,View会发送相应的指令给Controller,Controller接到指令,再去调用Model的方法去更新数据(大多是对数据的增删改查),Model处理完,View刷新显示。
MVC模式的缺点:
1:在android中,如果我们要用mvc模式,那么每层代表什么呢?
你可能会说:View对应android的layout.xml,Model对应android中对数据库的操作对网络等操作放在这里进行,Controller对应的则是Activity!
你说的都对,但是你不觉得这样的对应关系并不好吗,如果layout.xml对应View,那如果我们想动态的控制添加一些视图控件或者改变背景,那么该怎么办呢?
答曰:在Activity中添加代码。!!!这就是缺点之一所在:Activity既当爹(View)又当妈(Controller),layout.xml代表的View层控制能力太弱。
2:再看一遍我们的MVC的结构图,View和Model是互相联系的,存在耦合关系,这就给测试维护带来了难度。当我们想更换项目中的某个零件时,缺发现 太难拆下来!这个零件类的方法散布多处。关于MVC的结构图,忘了在哪听过一句经典的话,写三个字母,M,V,C,随便用线或箭头连字母,最后就是MVC的结构图。
说完了MVC,该主角登场了,上我们MVP的结构图。
好处不言而喻,View和Model无法通信了。
View层只负责与View有关的,操作View层时发出的事件传递给Presenter,Presenter去操作Model,操作完Model,再去通知View相应更新。
关于MVP的更多概念:
接下来,看看我们在项目中如何使用MVP模式,这里顺便使用了Retrofit和RXjava,建议你先了解它们的用法。
首先看我们的需求:输入Github登录名,点击搜索按钮,搜索并显示结果(登录名,昵称, followers,following)。
最终的项目结构:
bean类:
public class User {
private String login;
private String name;
private int followers;
private int following; public int getFollowers() {
return followers;
} public void setFollowers(int followers) {
this.followers = followers;
} public int getFollowing() {
return following;
} public void setFollowing(int following) {
this.following = following;
} public String getLogin() {
return login;
} public void setLogin(String login) {
this.login = login;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
}
retrofit类主要是封装了利用Retrofit的网络请求
public interface GithubService {
@GET("/users/{user}")
Observable<User> getUser(@Path("user") String username);
}
public class HttpMethods {
public static final String BASE_URL = "https://api.github.com"; private static final int DEFAULT_TIMEOUT = 5; private Retrofit retrofit;
private GithubService mGithubService; //构造方法私有
private HttpMethods() {
//手动创建一个OkHttpClient并设置超时时间
OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
httpClientBuilder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS); retrofit = new Retrofit.Builder()
.client(httpClientBuilder.build())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl(BASE_URL)
.build(); mGithubService = retrofit.create(GithubService.class);
}
private static class SingletonHolder{
private static final HttpMethods INSTANCE = new HttpMethods();
} //获取单例
public static HttpMethods getInstance(){
return SingletonHolder.INSTANCE;
} public void getUser(Subscriber<User> subscriber ,String loginName){
mGithubService.getUser(loginName)
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber); }
}
接下来思考我们的MVP模式了,一些从我们的View层开始,我们需要先列出和View相关的方法(不涉及逻辑)。
1.显示xml的试图
2.ProgressDialog显示
3.ProgressDialog消失
4.显示错误信息
接下来看具体代码:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
> <TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="80dp"/>
<EditText
android:id="@+id/ed_text"
android:layout_centerInParent="true"
android:hint="请输入搜索登录名"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/search_btn"
android:text="查询"
android:layout_centerHorizontal="true"
android:layout_below="@+id/ed_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RelativeLayout>
BaseView,BasePresentor , BaseModel三个接口
public interface BaseView {
void showProgressDialog();
void hideProgressDialog();
void showText(User userbean);
void showErrorMessage(String text);
}
public interface BasePresenter<T extends BaseView> {
void attachView(T view);
void detachView();
void searchUser(String loginName);
}
public interface BaseModel {
void getUser(Subscriber<User> subscribe,String loginName);
}
第二个接口interface BasePresenter<T extends BaseView>正是关键,至于为什么,可以用实现类去解释。
MainActivity实现BaseView接口,作为View层。
public class MainActivity extends AppCompatActivity implements BaseView { @InjectView(R.id.tv)
TextView mTextView;
@InjectView(R.id.search_btn)
Button mButton;
@InjectView(R.id.ed_text)
EditText mEditText; private ProgressDialog dialog;
private MainPresenter mMainPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.inject(this);
initView();
mMainPresenter=new MainPresenter();
mMainPresenter.attachView(this);
} /**
* 一些初始化,这里为ProgressDialog的初始化
*/
private void initView() {
dialog=new ProgressDialog(this);
dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
dialog.setMessage("正在搜索中");
} @OnClick(R.id.search_btn)
void search(View view){
mMainPresenter.searchUser(mEditText.getText().toString());
} @Override
public void showProgressDialog() {
dialog.show();
} @Override
public void hideProgressDialog() {
dialog.dismiss();
} @Override
public void showText(User userbean) {
String temp=getResources().getString(R.string.user_format);
String str=String.format(temp,userbean.getLogin(),userbean.getName(),userbean.getFollowers(),userbean.getFollowing());
mTextView.setText(str);
} @Override
public void showErrorMessage(String text) {
Toast.makeText(this,text,Toast.LENGTH_SHORT).show();
} @Override
protected void onDestroy() {
super.onDestroy();
if(mMainPresenter!=null)
mMainPresenter.detachView();
}
}
当点击Button产生事件时,是将逻辑交给MainPresenter去处理的,对应关系 V ——> P
下面看MainPresenter代码和Model代码。
public class MainPresenter implements BasePresenter {
private BaseView mMainView;
private MainModel mModel; public MainPresenter() {
mModel=new MainModel();
} @Override
public void attachView(BaseView view) {
mMainView=view;
} @Override
public void detachView() {
mMainView=null;
}
@Override
public void searchUser(String loginName) {
if(TextUtils.isEmpty(loginName.trim())){
mMainView.showErrorMessage("请输入合法登录名");
return;
}
if (mModel!=null){
mModel.getUser(new Subscriber<User>() {
@Override
public void onStart() { //先显示对话框
mMainView.showProgressDialog();
} @Override
public void onCompleted() { //请求结束,对话框消失
mMainView.hideProgressDialog(); } @Override
public void onError(Throwable e) { //error时
mMainView.showErrorMessage("搜索失败");
} @Override
public void onNext(User user) {
mMainView.showText(user);
}
},loginName);
} }
}
public class MainModel implements BaseModel{
@Override
public void getUser(Subscriber<User> subscriber ,String loginName) {
HttpMethods.getInstance().getUser(subscriber,loginName);
}
}
这里的Model实现类较为简单,直接使用了封装好的HttpMethods的方法。(Model可以理解为一个仓库管理员,我们的网络也能理解为一个大的仓库)。
在MainPresenter中我们其实是使用了Model的方法,即P——>M
然后用Rxjava的观察者观察结果,再去调用View的方法刷新界面,即P——>V
这时候回过来头来看我们的MVP图,是不是一模一样?(如何想要进阶mvp,可以试试契约类)
MVP模式入门(结合Rxjava,Retrofit)的更多相关文章
- MVP模式入门案例
随着UI创建技术的功能日益增强,UI层也履行着越来越多的职责.为了更好地细分视图(View)与模型(Model)的功能,让View专注于处理数据的可视化以及与用户的交互,同时让Model只关系数据的处 ...
- Android开发学习--MVP模式入门
1.模型与视图完全分离,我们可以修改视图而不影响模型2.可以更高效地使用模型,因为所有的交互都发生在一个地方——Presenter内部3.我们可以将一个Presenter用于多个视图,而不需要改变Pr ...
- MVP架构下解决 RxJava 自动解绑问题
背景 MVP 模式下使用 RxJava 处理网络访问的回调,当数据返回时 Presenter 调用绑定的 View 的方法. 定义 BasePresenter 如下: public class Bas ...
- RxJava+Retrofit+MVP构建的App——聚合资讯
RtfRxMVP 聚合资讯APP,提供热点资讯,天气预报以及笑话精选服务,使用 Retrofit + RxJava + MVP 构建代码. Hello U 这是我的一个练习项目,第一次尝试运用 MVP ...
- 开发 Material Design+RxJava+Retrofit+MVP App 参考资料
前言 在开发一个基于 Material Design+RxJava+Retrofit+MVP 框架的 App 过程中学习的资料整理 —— 由G军仔分享 这里记录了我开发 大象 项目时,所学习的 ...
- android打飞机游戏、MVP句子迷App、悬浮窗、RxJava+Retrofit、加载动画、定制计划App等源码
Android精选源码 微信打飞机 android进度设置加载效果源码 Android新手引导库EasyGuide MVP-好看又好用的句子迷客户端 XFloatView 一个简易的悬浮窗实现方案 a ...
- android完整资讯App、Kotlin新闻应用MVP + RxJava + Retrofit + Dagger2、优雅区间选择器等源码
Android精选源码 Android完整资讯客户端源码 android展示注册进度效果源码 Android Wifi热点数据传输Socket 通信示例源码 Android Dota的辅助信息app源 ...
- 手把手带你走进MVP +Dagger2 + DataBinding+ Rxjava+Retrofit 的世界
0.0 Android开发现在的变化用一个词来形容就是 :翻天覆地 越来越多的项目使用了MVP + Rxjava+Retrofit +Dagger2 + DataBinding等等东西.. 但是这些东 ...
- Rxjava + retrofit + dagger2 + mvp搭建Android框架
最近出去面试,总会被问到我们项目现在采用的什么开发框架,不过据我的经验网络框架(volley)+图片缓存(uIl)+数据库(orm)+mvp,不过现在这套框架比较好了,现在采用什么呢?Rxjava + ...
随机推荐
- js去掉字符串得第一个字符 、去掉字符串的最后一个字符
a1 = aa[0].slice(1); //去掉第一个字符串 a2 = a2.substr(0, a2.length - 1);
- GIT配置多用户
在公司工作的时候有时候想提交一点代码到github上,然后一台电脑上就需要配置两个账号分别访问github和公司的gitlab 1. 分别生成两个key 为什么要生成两个key的原因我也不清楚,望路过 ...
- C语言变量名转字符串的方法
C语言中将变量名转换成字符串使用的是#符号,来看下边两个宏定义: #define name2str(name) (#name) #define print_val(x) printf(#x" ...
- 【推荐系统实战】:C++实现基于用户的协同过滤(UserCollaborativeFilter)
好早的时候就打算写这篇文章,可是还是參加阿里大数据竞赛的第一季三月份的时候实验就完毕了.硬生生是拖到了十一假期.自己也是醉了... 找工作不是非常顺利,希望写点东西回想一下知识.然后再攒点人品吧,仅仅 ...
- Codeforces Round #256 (Div. 2) B. Suffix Structures(模拟)
题目链接:http://codeforces.com/contest/448/problem/B --------------------------------------------------- ...
- 微信公众号开发将war包导入新浪sae出现错误
JAVA_Error: Error for /wechat.do java.lang.NoSuchFieldError: INSTANCE at org.apache.http.impl.io.Def ...
- redis作为缓存场景使用,内存耗尽时,突然出现大量的逐出,在这个逐出的过程中阻塞正常的读写请求,导致 redis 短时间不可用
redis 突然大量逐出导致读写请求block 内容目录: 现象 背景 原因 解决方案 ref 现象 redis作为缓存场景使用,内存耗尽时,突然出现大量的逐出,在这个逐出的过程中阻塞正常的读写请 ...
- 4. idea常用快捷键设置(改为eclipse相似)
转自:https://blog.csdn.net/loveer0/article/details/82697877 idea常用快捷键设置(改为eclipse相似) 目录 idea常用快捷键设置改为e ...
- RMAN动态视图
1.V$ARCHIVEG_LOG 显示归档文件在数据库中创建.备份.清除 2.V$BACKUP_CORRUPTION 显示当一个备份集备份时块中发现的坏块 3.V$COPY_CORRUPTION 显示 ...
- AngularJs轻松入门(四)模块化
在前面几节教程中,代码比较少,为了方便说明问题笔者將控制器代码都写在了HTML页面中,实际上这并不是什么好的编程习惯,而且可维护性差.通常的做法都是將处理业务逻辑的代码写在一个单独的JS文件中,然后在 ...