在这里讲mvp模式的前提是需要大家有点接口回调的基础,也就是你懂得怎么回调接口,定义接口,理解接口。毕竟接口是解耦的利器哟,java的基础很重要~~
- 平常大部分人用的开发模式应该是mvc模式,相信大家对mvc模式也应该比较了解,在这里再唠叨一下其中的每个角色:m:通常我们是指数据模型和实体类,v:view通常指的是xml和页面显示的控件,而c:控制层则是指”万能的Activity”。
- 在上面为什么要说activity是万能的呢?因为我相信大家应该多多少少能够猜到,没错,在activity中布局文件中的数据绑定的操作,事件处理的代码都在activity中,造成了activity既像view又像controller,想想,其中的代码是不是动辄就得上百上千行代码,这就造成了activity里面的代码很繁杂臃肿,感觉啥都有activity来参与,代码混乱,思路完全混乱,而且这也跟android的设计思想—低耦合相悖,所以mvp应运而生了。
- 再来说说mvp的模式。为啥它一出来就收到很多人的热捧?其实,只要有一点的架构思想都能感觉的到其中的妙处,没有的话,那就多多体会其中代码的逻辑的清晰都,总会有点那种感觉;再说说里面的角色,v:activity页面或者fragment,m:没变还是model数据业务和实体,p:presenter,它其实是v和m层的中间者,其实我私底下认为它就是翻译者。这里现在不理解没事,接下来慢慢讲解。
- 接下来理解mvp其中的关系,不会有太多的生涩的字词,请先看图
我们能看到上面的是mvp的三者关系,其中view跟presenter是有双方通信的(看箭头),而model和presenter直接只有presenter持有model(箭头是单向的),那数据是如何传给presenter的呢,这就是上面开头说到的接口了,它通过接口回调的形式将数据库访问的结果或网络请求的结果返回给presenter,而p因为同时持有了view,所以将数据有传给了view,最终数据到了view层就非常easy了,直接update就好了。
- 接下来就开始撸代码了,代码非常easy,都能看得懂。
- 首先请看代码结构
<?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:id="@+id/activity_main"
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"
tools:context="com.sinodata.mvp.MainActivity">
<TextView
android:id="@+id/tvMsg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""/>
<ProgressBar
android:id="@+id/pb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:visibility="gone"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:onClick="loadData"
android:text="加载数据"/>
</RelativeLayout>
这里就是简单的一个button和一个textview,点击button将模拟数据请求,放在textview显示。
再看看包结构:
非常清晰,网络数据请求都到了model层了,view层只要定义好怎么显示看下这三层各个代码结构:
IModel层:
package com.sinodata.mvp.com.sinodata.mvp.view;
/**
* Created by Administrator on 2016/11/1.
*/
public interface IView {
void showMessage(String content);
void showDialog();
void hideDialog();
}
接着看model层的接口:
package com.sinodata.mvp.com.sinodata.mvp.model;
/**
* Created by Administrator on 2016/11/1.
* <p>
* model
* 请求网络数据业务模型
*/
public interface IModel {
void getMessage(ModelCallBack mCallBack);
}
这里定义了一个callBack用于回调网络数据结果给Presenter
Model的实现类代码:
package com.sinodata.mvp.com.sinodata.mvp.model;
import java.util.Random;
/**
* Created by Administrator on 2016/11/1.
* 业务实现类 正式加载网络数据业务
*/
public class ModelImp implements IModel {
@Override
public void getMessage(final ModelCallBack mCallBack) {
new Thread() {
@Override
public void run() {
super.run();
try {
//模拟网络请求
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Random r = new Random();
r.nextInt(1000);
//将数据通过接口回调给presenter层
mCallBack.getData("MVP:我是来自model业务层网络加载的数据 " + r);
}
}.start();
}
}
最后看看Presenter接口:
package com.sinodata.mvp.com.sinodata.mvp.presenter;
/**
* Created by Administrator on 2016/11/1.
*/
public interface IPresenter {
void loading();
}
这里就一个方法,用于到Activity中调用
接着看实现类Presenter:
package com.sinodata.mvp.com.sinodata.mvp.presenter;
import com.sinodata.mvp.com.sinodata.mvp.model.IModel;
import com.sinodata.mvp.com.sinodata.mvp.model.ModelCallBack;
import com.sinodata.mvp.com.sinodata.mvp.model.ModelImp;
import com.sinodata.mvp.com.sinodata.mvp.view.IView;
/**
* Created by Administrator on 2016/11/1.
* <p>
* 中间翻译者 同时持有view和model
*/
public class Presenter implements IPresenter {
private IModel mModel;
private IView mIView;
public Presenter(IView IView) {
mIView = IView;
mModel = new ModelImp();
}
@Override
public void loading() {
mIView.showDialog();
mModel.getMessage(new ModelCallBack() {
@Override
public void getData(String content) {
//在这里Presenter将数据开始传给了view层了
mIView.showMessage(content);
mIView.hideDialog();
}
});
}
}
最后还差一点就大功告成了,就是activity的实现IView接口:
package com.sinodata.mvp;
import android.app.ProgressDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.sinodata.mvp.com.sinodata.mvp.presenter.IPresenter;
import com.sinodata.mvp.com.sinodata.mvp.presenter.Presenter;
import com.sinodata.mvp.com.sinodata.mvp.view.IView;
public class MainActivity extends AppCompatActivity implements IView {
private TextView mTextView;
private IPresenter mIPresenter;
private ProgressBar pb;
private ProgressDialog mProgressDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.tvMsg);
pb = (ProgressBar) findViewById(R.id.pb);
pb.setKeepScreenOn(true);
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setCanceledOnTouchOutside(false);
//这里初始化presenter
mIPresenter = new Presenter(this);
}
public void loadData(View view) {
mIPresenter.loading();
}
@Override
public void showMessage(final String content) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mTextView.setText(content);
}
});
}
@Override
public void showDialog() {
//这里可以模拟弹出一个加载框
runOnUiThread(new Runnable() {
@Override
public void run() {
mProgressDialog.show();
}
});
}
@Override
public void hideDialog() {
//
runOnUiThread(new Runnable() {
@Override
public void run() {
mProgressDialog.hide();
}
});
}
}
好了代码里面的注释基本解释的清楚了,运行效果截图如下:
点击按钮button:
加载完数据效果如下:
是不是很easy?!!其实这是mvp最最简单的用法,里面还有很多需要完善的地方,比如,view的移除,生命周期控制等等,不过作为mvp模式的入门还是够得,本人也是对这个mvp模式研究没多久,但是很喜欢这种思想,后面会慢慢研究这个模式的思想,然后把博文发给大家看看,一起学习学习。