Model–View–Presenter (MVP) 源于 Model–View–Controller (MVC) 的结构设计模式,它是用于展示层(Presentation)的结构。
MVP 中的 Presenter 是 “中间人”角色,它的功能是在 Model–View–Presenter 三者中起到连接和协作的作用。程序中的大部分的逻辑都应该在 Presenter 中实现。
- Model 定义了数据的访问接口。例如之前文章 《App 组件化/模块化之路——Repository 模式》 就介绍了使用 Repository 实现数据访问的一种方式。
- View 定义了展示数据的接口,以及转发用户的指令
- Presenter 是连接 Model 与 View 的桥梁,是它们的协作者。
一、首先创建view 和 model接口
/**
* 定义基础UI逻辑
*/
public interface IView {
//定义初始化ui接口
void initUI();
//定义loading加载接口
void showLoading();
//显示数据接口
void showListViewData(List<News> listData);
}
/**
* 定义数据处理逻辑
*/
public interface IModel {
//读取数据接口
void loadData(OnLoadListener onLoadListener);
//内部接口用于实现回调
interface OnLoadListener{
void complete(List<News>listData);
}
}
其次,在创建presenter实现view 和model 的连接 :
public class IPresenter<T extends IView> {
//引入view实现
IView iView ;
//引入model实现
IModel iModel = new NewsImpl();
public IPresenter(T iView){
this.iView = iView ;
}
public void fetch(){
if(iView != null){
iView.initUI();
iView.showLoading();
}
if(iModel!= null){
iModel.loadData(new IModel.OnLoadListener() {
@Override
public void complete(List<News> listData) {
if(iView != null){
iView.showListViewData(listData);
}
}
});
}
}
}
这里需要有一个列表数据加载的实现:
public class NewsImpl implements IModel {
@Override
public void loadData(OnLoadListener onLoadListener) {
List<News> list = new ArrayList<News>();
list.add(new News("http://pic3.nipic.com/20090527/1242397_102231006_2.jpg","科技图片111"));
list.add(new News("http://pic29.nipic.com/20130601/12122227_123051482000_2.jpg","风景图片111"));
list.add(new News("http://t8.baidu.com/it/u=3660968530,985748925&fm=191&app=48&wm=1,17,90,45,20,7&wmo=0,0&n=0&g=0n&f=JPEG?sec=1853310920&t=9b4f100f0eedfe853fad24a58a4e1ad7","图片2222"));
list.add(new News("http://pic31.nipic.com/20130722/12473387_075510736124_2.jpg","图片33333"));
list.add(new News("http://pic3.nipic.com/20090702/918855_174429094_2.jpg","图片4444"));
list.add(new News("http://img.yanj.cn/store/goods/3488/3488_909a42564c7d2806ef3f87c4c5fe6029.jpg_max.jpg","图片5555"));
onLoadListener.complete(list);
}
}
我们实现了一个简单的listviewactivity,布局和adapter就不展示了,在activity实现Iview,代码如下:
public class MainActivity extends AppCompatActivity implements IView {
ListView listV ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//开始实现业务逻辑,条用presenter实现
new IPresenter<>(this).fetch();
}
@Override
public void initUI() {
//初始化ui接口实现
listV = (ListView) findViewById(R.id.list_v);
}
@Override
public void showLoading() {
//loading加载接口实现
Toast.makeText(this,"加载中...",Toast.LENGTH_SHORT).show();
}
@Override
public void showListViewData(List<News> listData) {
//数据加载完成回调处理
NewAdapter adapter = new NewAdapter(this,listData);
listV.setAdapter(adapter);
}
}
这样看起来代码很简洁,也很清晰,这就是一个简单的mpv架构模式的代码。
二、但是这样的代码在实际开发中还是会存在问题的,比如就有可能需要写很多这样的view-model-presenter,也有可能回引起activity内存泄露,所以在这里需要先加入软引用,优化泄露问题,首先修改Ipresenter:
public class IPresenter<T extends IView> {
WeakReference<T> viewRef ;
//引入view实现
IView iView ;
//引入model实现
IModel iModel = new NewsImpl();
public IPresenter(){
// this.iView = iView ;
}
//绑定
public void attachView(T view){
viewRef = new WeakReference<>(view);
}
//解绑
public void datachView(){
viewRef.clear();
}
public void fetch(){
if(viewRef.get() != null){
viewRef.get().initUI();
viewRef.get().showLoading();
}
if(iModel!= null){
iModel.loadData(new IModel.OnLoadListener() {
@Override
public void complete(List<News> listData) {
if(viewRef.get() != null){
viewRef.get().showListViewData(listData);
}
}
});
}
}
}
activity修改:
IPresenter iPresenter ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//开始实现业务逻辑,条用presenter实现
// new IPresenter<>(this).fetch();
iPresenter = new IPresenter();
iPresenter.attachView(this);
iPresenter.fetch();
}
@Override
protected void onDestroy() {
super.onDestroy();
iPresenter.datachView();
}
三、这样虽然避免了activity内存泄漏问题,但是后面所有的activity view 和 presenter进行绑定和解绑,冗余开发太多,所以这里可以将activity 和 ipresenter 向上抽一层:
抽取一个BaseActivity:
public abstract class BaseActivity<V , T extends IBasePresenter<V>> extends AppCompatActivity {
//表示层的引用
public T iPresenter ;
protected abstract T createPresenter();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
iPresenter = createPresenter();
iPresenter.attachView((V)this);
}
@Override
protected void onDestroy() {
super.onDestroy();
iPresenter.datachView();
}
}
抽取一个BasePresenter:
public class IBasePresenter<T > {
WeakReference<T> viewRef ;
//绑定view
public void attachView(T view){
viewRef = new WeakReference<>(view);
}
//解绑view
public void datachView(){
viewRef.clear();
}
}
那么activity需要修改为:
public class MainActivity extends BaseActivity<IView , IPresenter<IView>> implements IView {
ListView listV ;
@Override
protected IPresenter<IView> createPresenter() {
return new IPresenter<>();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//开始实现业务逻辑,调用presenter实现
// new IPresenter<>(this).fetch();
// iPresenter = new IPresenter();
// iPresenter.attachView(this);
iPresenter.fetch();
}
@Override
public void initUI() {
//初始化ui接口实现
listV = (ListView) findViewById(R.id.list_v);
}
@Override
public void showLoading() {
//loading加载接口实现
Toast.makeText(this,"加载中...",Toast.LENGTH_SHORT).show();
}
@Override
public void showListViewData(List<News> listData) {
//数据加载完成回调处理
NewAdapter adapter = new NewAdapter(this,listData);
listV.setAdapter(adapter);
}
}
IPresenter修改为:
public class IPresenter<T extends IView> extends IBasePresenter<T> {
//引入view实现
IView iView ;
//引入model实现
IModel iModel = new NewsImpl();
public IPresenter(){
// this.iView = iView ;
}
public void fetch(){
if(viewRef.get() != null){
viewRef.get().initUI();
viewRef.get().showLoading();
}
if(iModel!= null){
iModel.loadData(new IModel.OnLoadListener() {
@Override
public void complete(List<News> listData) {
if(viewRef.get() != null){
viewRef.get().showListViewData(listData);
}
}
});
}
}
}
此时即完成mvp的架构抽取。