java mvp模式_MVP模式入门(结合Rxjava,Retrofit)

本文MVP的sample实现效果:

b3a9b6d70822d2734187cd5d73f9bd19.gif

老规矩,在说对MVP模式的理解之前还是要再谈谈MVC模式,了解了MVC的缺点。我们才知道为什么要用MVP。

关于MVC的图解,我在网上找到了一些图。如下:

f6ce09c4b34b922ab5368c8a1526bc97.png   

2e15c2291b8c53e6d483d2b895264651.png

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的结构图。

3c575cb65df52a676a7cacd7dc370578.png

好处不言而喻,View和Model无法通信了。

View层只负责与View有关的,操作View层时发出的事件传递给Presenter,Presenter去操作Model,操作完Model,再去通知View相应更新。

关于MVP的更多概念:

接下来,看看我们在项目中如何使用MVP模式,这里顺便使用了Retrofit和RXjava,建议你先了解它们的用法。

首先看我们的需求:输入Github登录名,点击搜索按钮,搜索并显示结果(登录名,昵称, followers,following)。

最终的项目结构:

d8e8668b5973115d2469dbd2ae4d42ee.png      

3a705753125b38d9382063575fd00d04.png

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 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 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

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"

>

android:id="@+id/tv"

android:layout_width="match_parent"

android:layout_height="80dp"/>

android:id="@+id/ed_text"

android:layout_centerInParent="true"

android:hint="请输入搜索登录名"

android:layout_width="wrap_content"

android:layout_height="wrap_content"/>

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"/>

BaseView,BasePresentor , BaseModel三个接口

public interface BaseView {

void showProgressDialog();

void hideProgressDialog();

void showText(User userbean);

void showErrorMessage(String text);

}

public interface BasePresenter {

void attachView(T view);

void detachView();

void searchUser(String loginName);

}

public interface BaseModel {

void getUser(Subscriber subscribe,String loginName);

}

第二个接口interface BasePresenter正是关键,至于为什么,可以用实现类去解释。

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() {

@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 subscriber ,String loginName) {

HttpMethods.getInstance().getUser(subscriber,loginName);

}

}

这里的Model实现类较为简单,直接使用了封装好的HttpMethods的方法。(Model可以理解为一个仓库管理员,我们的网络也能理解为一个大的仓库)。

在MainPresenter中我们其实是使用了Model的方法,即P——>M

然后用Rxjava的观察者观察结果,再去调用View的方法刷新界面,即P——>V

这时候回过来头来看我们的MVP图,是不是一模一样?(如何想要进阶mvp,可以试试契约类)

4a68915fe728b81159c1924df47c65b7.png     

263f9d9ca24feecfc99a96dc46ff7eb9.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值