由于以前的MVC模式,不能很好的实现MODEL和View的分离,便出现了MVC模式的变种:MVP。
MVP模式的出现,就是为了彻底分离model与view,使项目的整理结构清晰。
由于MVP模式有很多变种,这些变种的出现多是为了处理MVP模式的一些短板,这些变种的区别大体上遵循的原则是实现model与view的分离,不同点在于对model,presenter,view的分工略有不同。
目前于我而言,还是处于一个学习的阶段,所以呢,还是从简单的易懂的方式开始学习。
我们以实例来学习编写这种模式,写程序之前,首先要明确的一点是:分工。
下面的实例分工原则是:view负责数据展示以及与用户交互,presenter负责view与model的通信,model负责获取数据。
任务分配完成,下面开始编码,以下实现的功能很简单,okhttp去请求一段图文列表并展示。
大致了解了MVP是干什么了以后,写代码感觉还是没什么思路,比如此时此刻的我。好吧,我们都知道MVP模式其实需要写很多的接口,这些接口实际上是为了实现模块之间的解耦。那么如何写这些接口呢?
首先,我们要做的就是从网络上载入一段列表数据到手机上展示。View层用来展示这些数据,那么首先就来写View层的接口。接口需要有的功能是加载过程中的进度条显示与隐藏,追加图文数据,加载失败或无数据。
public interface IImagesView
{
void addImageNews(List<ImageBean> imageNews);
void showLoadProgress();
void hideLoadProgress();
void showLoadFailed();
}
接着,我们知道MVP中的View通常指的是与用户交互的Fragment,Activity,View等。那么我们需要在Activity中去实现刚才定义的接口。
public class MainActivity extends Activity implements IImagesView
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public void addImageNews(List<ImageBean> imageNews)
{
}
@Override
public void showLoadProgress()
{
}
@Override
public void hideLoadProgress()
{
}
@Override
public void showLoadFailed()
{
}
}
接着继续思考,首先这个Activity作为View层接口的实现类,需要展示数据,那么这些数据从哪里来呢?我们清楚,数据需要从model中来,那么我们首先让model去获取数据。接着,定义一个接口用于处理获取数据成功或是失败的回掉处理。
public interface LoadImageNewsListener
{
void success(List<ImageBean> data);
void failed(String msg,Exception e);
}
定义一个用于model层加载数据的接口
/**
* model层加载数据接口类
* @author Administrator
*
*/
public interface IImageModel
{
void loadImageNews(LoadImageNewsListener listener);
}
定义Model层加载数据的实现类
/**
* Model层实现类,用于获取网络数据
*
* @author Administrator
*
*/
public class ImageModelImpl implements IImageModel
{
@Override
public void loadImageNews(final LoadImageNewsListener listener)
{
//这里发起请求数据,同时在拿到数据以后用接口去处理,这个接口在后续的Presener中实现具体的处理(Presener会将数据较给View的接口类处理)
OkGo.get(Urls.IMAGES_URL).cacheKey("imagenews").cacheMode(CacheMode.DEFAULT).execute(new StringCallback()
{
@Override
public void onSuccess(String arg0, okhttp3.Call arg1, okhttp3.Response arg2)
{
Log.i("resposne:", arg0);
Log.i("resposne:", arg2.body().toString());
listener.onSuccess(JSON.parseArray(arg2.body().toString(), ImageBean.class));
};
@Override
public void onError(okhttp3.Call call, okhttp3.Response response, Exception e)
{
Log.i("error:", response.body().toString());
Log.i("error:", e.getMessage());
listener.onFailed(response.body().toString(), e);
};
});
}
}
好了,现在MODEL已经取到数据,而View就等着去拿Model里的数据了,但是我们要让Model和View分离,显然,View中不可以持有model的引用,那么关键的地方到了,现在就用Presenter去实现。
/**
* Presenter实现类,要实现model与View的通信,并处理一些业务逻辑
*
* @author Administrator
*
*/
public class ImagePresenterImpl implements IImageNewsPresenter, LoadImageNewsListener
{
private IImagesView mIImagesView;
private IImageModel mIImageModel;
public ImagePresenterImpl(IImagesView iamgeview, IImageModel imagemodel)
{
this.mIImagesView = iamgeview;
this.mIImageModel = imagemodel;
}
@Override
public void loadImageNews()
{
mIImagesView.showLoadProgress();
mIImageModel.loadImageNews(this);
}
@Override
public void onSuccess(List<ImageBean> data)
{
mIImagesView.hideLoadProgress();
mIImagesView.addImageNews(data);
}
@Override
public void onFailed(String msg, Exception e)
{
mIImagesView.hideLoadProgress();
mIImagesView.showLoadFailed();
}
}
到这里除了还没有在View中显示出来,其实大部分逻辑都写完了,将前后的流程串起来后,其实我做了这么一件事。
一、我在model层中定义了一个去获取数据的接口 IImageModel ,然后再model层的实现类 ImageModelImpl 中发请求从网络端去获取数据。
二、model层的接口方法 loadImageNews 的参数列表中持有一个和Presener层通信的引用接口 LoadImageNewsListener(这个接口处理加载数据成功与失败)。
三、在Presener层中我定义了一个接口用于加载数据,同时在Presener的实现类中实现了两个接口,分别为Presener层中加载数据的接口,和加载数据结果的监听接口(这个接口在model层中获取数据时保留有引用);同时,Presener层持有Model层的接口引用和View层的接口引用,分别处理了下面这些事:1、加载数据时通知View的接口显示进度条,同时通知model取获取数据。2、实现了获取数据结果以后的处理,若成功,通知View的接口类隐藏进度条,同时通知View的接口类加载数据;失败则通知View接口类隐藏进度条,同时显示出错误信息。
OK,以上描述不知各位是否思路上会有一点清晰了呢?其实我们还有事情没有做,现在Presener让model取到数据后,通知View接口类去做的事情,不知道View做了没有呢?
显然,还没有做呢,View接口类的实现类其实就是MainActivity,这就是我们所说的View,MainActivity实现了View的接口类,我们需要做的事情是,实现其中的方法,同时把从Presener抽出来的数据显示出来,如下:
public class MainActivity extends Activity implements IImagesView
{
private ListView mListView;
private ImageAdapter mAdapter;
private Dialog mDialog;
private IImageNewsPresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = (ListView) findViewById(R.id.listview);
mAdapter = new ImageAdapter(this);
presenter = new ImagePresenterImpl(this);
mListView.setAdapter(mAdapter);
presenter.loadImageNews();
}
@Override
public void addImageNews(List<ImageBean> imageNews)
{
mAdapter.refreshData(imageNews);
}
@Override
public void showLoadProgress()
{
mDialog = new ProgressDialog(this);
mDialog.show();
}
@Override
public void hideLoadProgress()
{
if (null != mDialog)
{
mDialog.dismiss();
}
}
@Override
public void showLoadFailed()
{
Toast.makeText(this, "访问出现错误......", Toast.LENGTH_LONG).show();
}
}
由此,我们可以总结出mvp模式的一般特点:
* Model层,数据层,主要负责网络层和数据库层的交互
* View层,UI层,主要负责数据的显示,并向Presener报告用户的行为
* Presener,从Model层中取数据,并应用到UI层,决定UI层要显示什么,并响应用户的行为.
·