为什么使用MVP?
一般在Activity中既要写关于界面渲染 用户处理的代码 又要处理关于网络 数据库的请求,如果一个界面的功能复杂,那么就很容易在Activity中造成代码混乱,引用MVP 可以使代码结构逻辑更加清晰,业务逻辑与界面的剥离,解耦。
MVP实际上分为三个概念
- View 对应于Activity、Fragment,负责View的绘制以及与用户交互
- Model 业务逻辑和实体模型
- Presenter 负责完成View于Model间的交互 让View与Model之间完全剥离,通过Presenter作为媒介,使两者起交互作用。
举个例子:
加载一串数据显示在TextView中,Model就是负责去加载这个数据,View就是显示TextView,如何把数据显示到TextView中呢? 就是通过Presenter去调用Model加载数据,然后通过接口返回给View。
根据这上面这个例子,按照流程编写成一个简单demo(点击按钮 模拟一个网络请求 在请求的过程中展示加载框 并在数据加载完成后隐藏加载框和展示网络请求结果):
1.既然MVC是由3个模块组成,这里首先为MainActivity定义IMainView接口规范
public interface IMainView {
}
public class MainActivity extends AppCompatActivity implements IMainView {
}
2.定义布局界面
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="asyncRequest"
android:text="模拟异步请求" />
<TextView
android:id="@+id/result_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
3.初始化布局控件
public class MainActivity extends AppCompatActivity implements IMainView {
private TextView mResultTv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mResultTv =(TextView) findViewById(R.id.result_tv);
}
//按钮点击事件
public void asyncRequest(View v){
}
}
4.点击按钮执行asyncRequest方法。接着由View层告诉Presenter层处理网络请求,这里先创建Presenter层,由于上面Presenter层与View层交流,所以这里Presenter层必须持有View层。代码如下。
public interface IShowPresenter {
//定义模拟的网络请求
public void doNetworkRequest();
}
public class ShowPresenterImpl implements IShowPresenter{
private IMainView mMainView;
public ShowPresenterImpl(IMainView mainView) {
mMainView=mainView;
}
@Override
public void doNetworkRequest() {
}
}
5.在View层中,onCreate()方法创建Presenter层,当点击按钮,通知Presenter层做网络请求。
public class MainActivity extends AppCompatActivity implements IMainView {
...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
//初始化Presenter层
mPresenter=new ShowPresenterImpl(this);
}
public void asyncRequest(View v){
//开始网络请求
mPresenter.doNetworkRequest();
}
//显示对话框
@Override
public void showProgress(String s) {
mDialog=new ProgressDialog(this);
mDialog.setMessage(s);
mDialog.show();
}
}
public class ShowPresenterImpl implements IShowPresenter{
...
@Override
public void doNetworkRequest() {
//1.展示数据加载对话框
mMainView.showProgress("模拟数据正在加载中...");
//2.做网络请求 TODO
...
}
}
6.实际上,Presenter层只是做为一个中间件,真正的网络请求是Model层,所以这里首先创建Model层,并定义网络请求的规范。
public interface IShowModel {
void doNetworkRequest();
}
public class ShowModelImpl implements IShowModel {
private IShowListener mListener;
private Handler mHandler=new Handler(){
@Override
public void handleMessage(Message msg) {
//数据如何返回呢? (String) msg.obj
//TODO
}
};
@Override
public void doNetworkRequest() {
new Thread(){
@Override
public void run() {
SystemClock.sleep(3000);
String mockData="模拟请求的数据完毕。。。";
mHandler.obtainMessage(0,mockData).sendToTarget();
}
}.start();
}
}
6.上面的Model层提供了一个网络请求的方法doNetworkRequest(),该方法由Presenter层调用。
public class ShowPresenterImpl implements IShowPresenter,IShowModel.IShowListener{
...
private IShowModel mShowModel;
public ShowPresenterImpl(IMainView mainView) {
...
mShowModel=new ShowModelImpl(this);
}
@Override
public void doNetworkRequest() {
//1.展示数据加载对话框
...
//2.做网络请求
mShowModel.doNetworkRequest();
}
}
7.数据在Model层请求完毕后,需要将数据告诉Presenter层先,这里定义了一个回调接口。
public interface IShowModel {
...
public static interface IShowListener{
void onNetworkRequestFinish(String result);
}
}
8.Presenter是被通知的对象,所以也是回调接口的继承者,继承了回调接口后还要通知Model层。
public class ShowPresenterImpl implements IShowPresenter,IShowModel.IShowListener{
public ShowPresenterImpl(IMainView mainView) {
...
//将回调接口告诉Model层
mShowModel=new ShowModelImpl(this);
}
//实现回调接口的方法
@Override
public void onNetworkRequestFinish(String result) {
...
}
}
9.Model层数据请求结束后 通过回调接口告诉Presenter层。
public class ShowModelImpl implements IShowModel {
private IShowListener mListener;
private Handler mHandler=new Handler(){
@Override
public void handleMessage(Message msg) {
//数据如何返回呢?
if (mListener!=null){
mListener.onNetworkRequestFinish((String) msg.obj);
}
}
};
public ShowModelImpl(IShowListener mListener) {
this.mListener = mListener;
}
...
}
10.Presenter接收到网络请求的接口 告诉View层隐藏记载框并且修改显示的UI。
public class ShowPresenterImpl implements IShowPresenter,IShowModel.IShowListener{
...
@Override
public void onNetworkRequestFinish(String result) {
//3.修改UI
mMainView.resetResultTv(result);
//4.隐藏数据加载的对话框
mMainView.hideProgress();
}
}
public class MainActivity extends AppCompatActivity implements IMainView {
...
@Override
public void hideProgress() {
if (mDialog!=null){
mDialog.dismiss();
}
}
@Override
public void resetResultTv(String result) {
mResultTv.setText(result);
}
}
示例结果:
总结
感觉上单纯为了简单的实现,而去写这么多的代码,但是逻辑和结构上是更加地清晰了,业务和界面实现的方式完全剥离开。在实际的项目中这种做法更利于后期的开发和维护。