当下开发中使用最多的最普遍的有三种模式就是MVC,MVP和MVVM。相信大家对这三个名词并不陌生,他们在我们的开发用应用的及其广泛,今天我就浅谈一下我了解的MVP设计模式。说MVP之前不得不谈谈MVC模式,MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方我们充分的认识了MVC的不足,才能更好地使用MVP。希望大家看完都有所收获。
转载请标明出处:
本文来自【周焰权的博客】
首先给出MVC和MVP的结构图,现在具体说一下MVC的不足
(1)View层和Controller层任务分工不明
Controller负责逻辑的处理,Model提供数据,View负责显示。当我们在android开发中想要动态的添加一些视图控件的时候,你可能会在Activity的代码中添加。咋一看并没有什么错,合情合理。但你认为这样很好吗?
答案肯定是否定的,因为在这里Activity既当妈(View)又当了爹(Controller),是的layout.xml的控制力变弱,影响了各层的性能。这样也不利于团队的开发
(2)View层和Model的耦合度高
细心的同学估计已经看出MVC结构图,View层和Model是相互联系的,存在耦合关系初期的小项目和能接受,但严重影响之后程序的可扩展性,会让代码的可读性越来越差。如果你想更换项目中的部分代码,你会发现了太难了,这些零散的类散布的到处都是。不仅如此,因为有一些业务逻辑在View里实现了,导致要更改View也是比较困难的,至少那些业务逻辑是无法重用的。所以今天来谈谈MVP模式。
MVP模式结构
- Model: 业务逻辑和实体模型
- View:用户交互和视图显示,在android中对应activity
- Presenter: 负责完成View于Model间的逻辑和交互
首先你要有个请求数据的类
public interface GetData { //去请求数据 @Headers({"Content-Type:application/json; charset=UTF-8"})//请求头 @POST(value = "v1/tag/cartoon")//后半部分的请求地址 Call<Cartoon> getListData(@Query("page_size ") String page_size, @Query("page") String page); }
然后请求是否成功的回掉
public interface OnGetDataListenser { //请求成功这里的Cartoon是你的bean类 void onSuccessGetDataListener(Cartoon cartoon); //失败 void onFailGetDataListener(String erro); }
在然后你要有个Model的管理接口,要知道MVP其实就是一种更纯粹的面向对象编程,它直接面向接口
public interface INetWorkModel { //请求数据 void loadData(int page); }
然后用NetWorkModel去实现INetWorkModel这个接口,实现他的方法
public class NetWorkModel implements INetWorkModel { OnGetDataListenser onGetDataListenser; public NetWorkModel(OnGetDataListenser onGetDataListenser){ this.onGetDataListenser = onGetDataListenser; } //加载数据 @Override public void loadData(int page) { HttpUtils httpUtils = HttpUtils.getHttpUtils(); //进行网络请求 httpUtils.getListData("http://api.menghuoapp.com/",page+""); httpUtils.setOnGetDataListenser(onGetDataListenser); } }
这里的数据请求,用个单例模式
public class HttpUtils { private OnGetDataListenser onGetDataListenser; public void setOnGetDataListenser(OnGetDataListenser onGetDataListenser){ this.onGetDataListenser = onGetDataListenser; } //提供一个对象:使用单例模式 private static HttpUtils httpUtils; public static HttpUtils getHttpUtils(){ if(httpUtils==null){ httpUtils = new HttpUtils(); } return httpUtils; } //进行网络请求数据 //baseUrl:请求接口的前半部分 public void getListData(String baseUrl,String page){ Retrofit retrofit = new Retrofit.Builder() .baseUrl(baseUrl) .addConverterFactory(GsonConverterFactory.create()) .build(); GetData getData = retrofit.create(GetData.class); Call<Cartoon> call =getData.getListData("5",page); call.enqueue(new Callback<Cartoon>() { @Override public void onResponse(Call<Cartoon> call, Response<Cartoon> response) { if(onGetDataListenser!=null){ onGetDataListenser.onSuccessGetDataListener(response.body()); } } @Override public void onFailure(Call<Cartoon> call, Throwable t) { if(onGetDataListenser!=null){ onGetDataListenser.onFailGetDataListener(t.getMessage()); } } }); } }这是Model层的几个类,我们来写Persenter的类还记不记得之前的监听回调接口 ,让Persenter类去实现
public class NetWorkPresenter implements OnGetDataListenser{ INetWorkView iNetWorkView; INetWorkModel iNetWorkModel; public NetWorkPresenter(INetWorkView iNetWorkView){ this.iNetWorkView = iNetWorkView; iNetWorkModel = new NetWorkModel(this); } public void getListData(int page){ iNetWorkModel.loadData(page); } @Override public void onSuccessGetDataListener(Cartoon cartoon) { iNetWorkView.setData(cartoon); } @Override public void onFailGetDataListener(String erro) { iNetWorkView.setFailMessage(erro); } }
始终记住面向对象的思想,我们定义View的管理接口
public interface INetWorkView { //给ListView的数据 void setData(Cartoon cartoon); //请求失败的信息 void setFailMessage(String erro); }
同样让你要展示的View类来实现这个接口
public class NetWorkActivity extends AppCompatActivity implements INetWorkView{ private ListView lv; private NetWorkPresenter netWorkPresenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_net_work_activitye); lv = (ListView) findViewById(R.id.lv); //进行网络请求 netWorkPresenter = new NetWorkPresenter(this); netWorkPresenter.getListData(1); } @Override public void setData(Cartoon cartoon) { //cartoon 是数据源 //adapter //使用Adapter将数据展示到ListView lv.setAdapter(new MyAdapter(NetWorkActivity.this,cartoon.getData())); Log.e("AAA","请求成功"+cartoon.getMsg()); Log.e("AAA","请求成功"+cartoon.getData().size()); } @Override public void setFailMessage(String erro) { Log.e("AAA","请求失败"+erro); } }
同样给出自定义的adapter的类和bean类
public class MyAdapter extends BaseAdapter { private Context context; private List<Cartoon.DataBean> list ; public MyAdapter(Context context, List<Cartoon.DataBean> list){ this.context= context; this.list = list; } @Override public int getCount() { return list==null?0:list.size(); } @Override public Object getItem(int position) { return list.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ImageView imageView = new ImageView(context); Picasso.with(context).load(list.get(position).getPic_url()).into(imageView); return imageView; } }
public class Cartoon { private String msg; private int code; private List<DataBean> data; public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public int getCode() { return code; } public void setCode(int code) { this.code = code; } public List<DataBean> getData() { return data; } public void setData(List<DataBean> data) { this.data = data; } public static class DataBean { private String link; private String title; private String subtitle; private String pic_url; public String getLink() { return link; } public void setLink(String link) { this.link = link; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getSubtitle() { return subtitle; } public void setSubtitle(String subtitle) { this.subtitle = subtitle; } public String getPic_url() { return pic_url; } public void setPic_url(String pic_url) { this.pic_url = pic_url; } } }
总结一下
在处理复杂界面和逻辑时,我们可以对同一个activity将每一个业务都抽离成一 个Presenter,这样代码既清晰逻辑明确又方便我们扩展。